+ikiwiki.setup
Makefile
Makefile.old
blib/*
pm_to_blib
*.man
build-stamp
+po/po2wiki_stamp
+po/underlays/*/*.mdwn
+po/underlays/basewiki/*/*.mdwn
+po/underlays/basewiki/*/*/*.mdwn
+po/underlays/directives/ikiwiki/directive/*.mdwn
+po/underlays_copy_stamp
+underlays/locale
# when they are part of the core program. I don't plan to have more than
# the one exporting module in IkiWiki, so let's ignore this test.
[-Modules::RequireFilenameMatchesPackage]
-# IkiWIki also switches _out_ of the core package when a package namespace
+# IkiWiki also switches _out_ of the core package when a package namespace
# is a good way to group a set of functions. This doesn't mean I want it
# loading up a separate file though, so it's in the same file.
[-Modules::ProhibitMultiplePackages]
=head1 CONTENTS
-XML::Simple
Text::Markdown
-Date::Parse
-HTML::Template
HTML::Scrubber
-CGI
+HTML::Template
+HTML::Parser
+URI
+XML::Simple
+Date::Parse
CGI::FormBuilder
CGI::Session
Mail::Sendmail
-HTML::Parser
-URI
+CGI
Data::Dumper
=head1 AUTHOR
Text::WikiFormat
XML::Feed
Net::Amazon::S3
+Text::WikiCreole
+Term::ReadLine::Gnu
+HTML::Tree
+Sort::Naturally
=head1 AUTHOR
#!/usr/bin/perl
package IkiWiki;
+
use warnings;
use strict;
use Encode;
use open qw{:utf8 :std};
use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase
- %pagestate %renderedfiles %oldrenderedfiles %pagesources
- %destsources %depends %hooks %forcerebuild $gettext_obj};
+ %pagestate %wikistate %renderedfiles %oldrenderedfiles
+ %pagesources %destsources %depends %hooks %forcerebuild
+ %loaded_plugins};
use Exporter q{import};
our @EXPORT = qw(hook debug error template htmlpage add_depends pagespec_match
- bestlink htmllink readfile writefile pagetype srcfile pagename
- displaytime will_render gettext urlto targetpage
- add_underlay
- %config %links %pagestate %renderedfiles
+ pagespec_match_list bestlink htmllink readfile writefile
+ pagetype srcfile pagename displaytime will_render gettext urlto
+ targetpage add_underlay pagetitle titlepage linkpage
+ newpagefile inject add_link
+ %config %links %pagestate %wikistate %renderedfiles
%pagesources %destsources);
-our $VERSION = 2.00; # plugin interface version, next is ikiwiki version
+our $VERSION = 3.00; # plugin interface version, next is ikiwiki version
our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE
-my $installdir=''; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE
+our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE
# Optimisation.
use Memoize;
memoize("pagespec_translate");
memoize("file_pruned");
-sub defaultconfig () { #{{{
- return
- wiki_file_prune_regexps => [qr/(^|\/)\.\.(\/|$)/, qr/^\./, qr/\/\./,
- qr/\.x?html?$/, qr/\.ikiwiki-new$/,
- qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//,
- qr/(^|\/)_MTN\//,
- qr/\.dpkg-tmp$/],
- wiki_file_regexp => qr/(^[-[:alnum:]_.:\/+]+$)/,
- web_commit_regexp => qr/^web commit (by (.*?(?=: |$))|from (\d+\.\d+\.\d+\.\d+)):?(.*)/,
- verbose => 0,
- syslog => 0,
- wikiname => "wiki",
- default_pageext => "mdwn",
- htmlext => "html",
- cgi => 0,
- post_commit => 0,
- rcs => '',
- url => '',
- cgiurl => '',
- historyurl => '',
- diffurl => '',
- rss => 0,
- atom => 0,
- allowrss => 0,
- allowatom => 0,
- discussion => 1,
- rebuild => 0,
- refresh => 0,
- getctime => 0,
- w3mmode => 0,
- wrapper => undef,
- wrappermode => undef,
- svnpath => "trunk",
- gitorigin_branch => "origin",
- gitmaster_branch => "master",
- srcdir => undef,
- destdir => undef,
- pingurl => [],
- templatedir => "$installdir/share/ikiwiki/templates",
- underlaydir => "$installdir/share/ikiwiki/basewiki",
- underlaydirs => [],
- setup => undef,
- adminuser => undef,
- adminemail => undef,
- plugin => [qw{mdwn link inline htmlscrubber passwordauth openid
- signinedit lockedit conditional recentchanges}],
- libdir => undef,
- timeformat => '%c',
- locale => undef,
- sslcookie => 0,
- httpauth => 0,
- userdir => "",
- usedirs => 1,
- numbacklinks => 10,
- account_creation_password => "",
- prefix_directives => 0,
- hardlink => 0,
- cgi_disable_uploads => 1,
-} #}}}
-
-sub checkconfig () { #{{{
+sub getsetup () {
+ wikiname => {
+ type => "string",
+ default => "wiki",
+ description => "name of the wiki",
+ safe => 1,
+ rebuild => 1,
+ },
+ adminemail => {
+ type => "string",
+ default => undef,
+ example => 'me@example.com',
+ description => "contact email for wiki",
+ safe => 1,
+ rebuild => 0,
+ },
+ adminuser => {
+ type => "string",
+ default => [],
+ description => "users who are wiki admins",
+ safe => 1,
+ rebuild => 0,
+ },
+ banned_users => {
+ type => "string",
+ default => [],
+ description => "users who are banned from the wiki",
+ safe => 1,
+ rebuild => 0,
+ },
+ srcdir => {
+ type => "string",
+ default => undef,
+ example => "$ENV{HOME}/wiki",
+ description => "where the source of the wiki is located",
+ safe => 0, # path
+ rebuild => 1,
+ },
+ destdir => {
+ type => "string",
+ default => undef,
+ example => "/var/www/wiki",
+ description => "where to build the wiki",
+ safe => 0, # path
+ rebuild => 1,
+ },
+ url => {
+ type => "string",
+ default => '',
+ example => "http://example.com/wiki",
+ description => "base url to the wiki",
+ safe => 1,
+ rebuild => 1,
+ },
+ cgiurl => {
+ type => "string",
+ default => '',
+ example => "http://example.com/wiki/ikiwiki.cgi",
+ description => "url to the ikiwiki.cgi",
+ safe => 1,
+ rebuild => 1,
+ },
+ cgi_wrapper => {
+ type => "string",
+ default => '',
+ example => "/var/www/wiki/ikiwiki.cgi",
+ description => "filename of cgi wrapper to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ cgi_wrappermode => {
+ type => "string",
+ default => '06755',
+ description => "mode for cgi_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ rcs => {
+ type => "string",
+ default => '',
+ description => "rcs backend to use",
+ safe => 0, # don't allow overriding
+ rebuild => 0,
+ },
+ default_plugins => {
+ type => "internal",
+ default => [qw{mdwn link inline meta htmlscrubber passwordauth
+ openid signinedit lockedit conditional
+ recentchanges parentlinks editpage}],
+ description => "plugins to enable by default",
+ safe => 0,
+ rebuild => 1,
+ },
+ add_plugins => {
+ type => "string",
+ default => [],
+ description => "plugins to add to the default configuration",
+ safe => 1,
+ rebuild => 1,
+ },
+ disable_plugins => {
+ type => "string",
+ default => [],
+ description => "plugins to disable",
+ safe => 1,
+ rebuild => 1,
+ },
+ templatedir => {
+ type => "string",
+ default => "$installdir/share/ikiwiki/templates",
+ description => "location of template files",
+ advanced => 1,
+ safe => 0, # path
+ rebuild => 1,
+ },
+ underlaydir => {
+ type => "string",
+ default => "$installdir/share/ikiwiki/basewiki",
+ description => "base wiki source location",
+ advanced => 1,
+ safe => 0, # path
+ rebuild => 0,
+ },
+ underlaydirbase => {
+ type => "internal",
+ default => "$installdir/share/ikiwiki",
+ description => "parent directory containing additional underlays",
+ safe => 0,
+ rebuild => 0,
+ },
+ wrappers => {
+ type => "internal",
+ default => [],
+ description => "wrappers to generate",
+ safe => 0,
+ rebuild => 0,
+ },
+ underlaydirs => {
+ type => "internal",
+ default => [],
+ description => "additional underlays to use",
+ safe => 0,
+ rebuild => 0,
+ },
+ verbose => {
+ type => "boolean",
+ example => 1,
+ description => "display verbose messages?",
+ safe => 1,
+ rebuild => 0,
+ },
+ syslog => {
+ type => "boolean",
+ example => 1,
+ description => "log to syslog?",
+ safe => 1,
+ rebuild => 0,
+ },
+ usedirs => {
+ type => "boolean",
+ default => 1,
+ description => "create output files named page/index.html?",
+ safe => 0, # changing requires manual transition
+ rebuild => 1,
+ },
+ prefix_directives => {
+ type => "boolean",
+ default => 1,
+ description => "use '!'-prefixed preprocessor directives?",
+ safe => 0, # changing requires manual transition
+ rebuild => 1,
+ },
+ indexpages => {
+ type => "boolean",
+ default => 0,
+ description => "use page/index.mdwn source files",
+ safe => 1,
+ rebuild => 1,
+ },
+ discussion => {
+ type => "boolean",
+ default => 1,
+ description => "enable Discussion pages?",
+ safe => 1,
+ rebuild => 1,
+ },
+ discussionpage => {
+ type => "string",
+ default => gettext("Discussion"),
+ description => "name of Discussion pages",
+ safe => 1,
+ rebuild => 1,
+ },
+ sslcookie => {
+ type => "boolean",
+ default => 0,
+ description => "only send cookies over SSL connections?",
+ advanced => 1,
+ safe => 1,
+ rebuild => 0,
+ },
+ default_pageext => {
+ type => "string",
+ default => "mdwn",
+ description => "extension to use for new pages",
+ safe => 0, # not sanitized
+ rebuild => 0,
+ },
+ htmlext => {
+ type => "string",
+ default => "html",
+ description => "extension to use for html files",
+ safe => 0, # not sanitized
+ rebuild => 1,
+ },
+ timeformat => {
+ type => "string",
+ default => '%c',
+ description => "strftime format string to display date",
+ advanced => 1,
+ safe => 1,
+ rebuild => 1,
+ },
+ locale => {
+ type => "string",
+ default => undef,
+ example => "en_US.UTF-8",
+ description => "UTF-8 locale to use",
+ advanced => 1,
+ safe => 0,
+ rebuild => 1,
+ },
+ userdir => {
+ type => "string",
+ default => "",
+ example => "users",
+ description => "put user pages below specified page",
+ safe => 1,
+ rebuild => 1,
+ },
+ numbacklinks => {
+ type => "integer",
+ default => 10,
+ description => "how many backlinks to show before hiding excess (0 to show all)",
+ safe => 1,
+ rebuild => 1,
+ },
+ hardlink => {
+ type => "boolean",
+ default => 0,
+ description => "attempt to hardlink source files? (optimisation for large files)",
+ advanced => 1,
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ umask => {
+ type => "integer",
+ example => "022",
+ description => "force ikiwiki to use a particular umask",
+ advanced => 1,
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ wrappergroup => {
+ type => "string",
+ example => "ikiwiki",
+ description => "group for wrappers to run in",
+ advanced => 1,
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ libdir => {
+ type => "string",
+ default => "",
+ example => "$ENV{HOME}/.ikiwiki/",
+ description => "extra library and plugin directory",
+ advanced => 1,
+ safe => 0, # directory
+ rebuild => 0,
+ },
+ ENV => {
+ type => "string",
+ default => {},
+ description => "environment variables",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ exclude => {
+ type => "string",
+ default => undef,
+ example => '\.wav$',
+ description => "regexp of source files to ignore",
+ advanced => 1,
+ safe => 0, # regexp
+ rebuild => 1,
+ },
+ wiki_file_prune_regexps => {
+ type => "internal",
+ default => [qr/(^|\/)\.\.(\/|$)/, qr/^\./, qr/\/\./,
+ qr/\.x?html?$/, qr/\.ikiwiki-new$/,
+ qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//,
+ qr/(^|\/)_MTN\//, qr/(^|\/)_darcs\//,
+ qr/\.dpkg-tmp$/],
+ description => "regexps of source files to ignore",
+ safe => 0,
+ rebuild => 1,
+ },
+ wiki_file_chars => {
+ type => "string",
+ description => "specifies the characters that are allowed in source filenames",
+ default => "-[:alnum:]+/.:_",
+ safe => 0,
+ rebuild => 1,
+ },
+ wiki_file_regexp => {
+ type => "internal",
+ description => "regexp of legal source files",
+ safe => 0,
+ rebuild => 1,
+ },
+ web_commit_regexp => {
+ type => "internal",
+ default => qr/^web commit (by (.*?(?=: |$))|from (\d+\.\d+\.\d+\.\d+)):?(.*)/,
+ description => "regexp to parse web commits from logs",
+ safe => 0,
+ rebuild => 0,
+ },
+ cgi => {
+ type => "internal",
+ default => 0,
+ description => "run as a cgi",
+ safe => 0,
+ rebuild => 0,
+ },
+ cgi_disable_uploads => {
+ type => "internal",
+ default => 1,
+ description => "whether CGI should accept file uploads",
+ safe => 0,
+ rebuild => 0,
+ },
+ post_commit => {
+ type => "internal",
+ default => 0,
+ description => "run as a post-commit hook",
+ safe => 0,
+ rebuild => 0,
+ },
+ rebuild => {
+ type => "internal",
+ default => 0,
+ description => "running in rebuild mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ setup => {
+ type => "internal",
+ default => undef,
+ description => "running in setup mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ refresh => {
+ type => "internal",
+ default => 0,
+ description => "running in refresh mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ test_receive => {
+ type => "internal",
+ default => 0,
+ description => "running in receive test mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ getctime => {
+ type => "internal",
+ default => 0,
+ description => "running in getctime mode",
+ safe => 0,
+ rebuild => 0,
+ },
+ w3mmode => {
+ type => "internal",
+ default => 0,
+ description => "running in w3mmode",
+ safe => 0,
+ rebuild => 0,
+ },
+ wikistatedir => {
+ type => "internal",
+ default => undef,
+ description => "path to the .ikiwiki directory holding ikiwiki state",
+ safe => 0,
+ rebuild => 0,
+ },
+ setupfile => {
+ type => "internal",
+ default => undef,
+ description => "path to setup file",
+ safe => 0,
+ rebuild => 0,
+ },
+ allow_symlinks_before_srcdir => {
+ type => "boolean",
+ default => 0,
+ description => "allow symlinks in the path leading to the srcdir (potentially insecure)",
+ safe => 0,
+ rebuild => 0,
+ },
+}
+
+sub defaultconfig () {
+ my %s=getsetup();
+ my @ret;
+ foreach my $key (keys %s) {
+ push @ret, $key, $s{$key}->{default};
+ }
+ use Data::Dumper;
+ return @ret;
+}
+
+sub checkconfig () {
# locale stuff; avoid LC_ALL since it overrides everything
if (defined $ENV{LC_ALL}) {
$ENV{LANG} = $ENV{LC_ALL};
if (defined $config{locale}) {
if (POSIX::setlocale(&POSIX::LC_ALL, $config{locale})) {
$ENV{LANG}=$config{locale};
- $gettext_obj=undef;
+ define_gettext();
}
}
+
+ if (! defined $config{wiki_file_regexp}) {
+ $config{wiki_file_regexp}=qr/(^[$config{wiki_file_chars}]+$)/;
+ }
if (ref $config{ENV} eq 'HASH') {
foreach my $val (keys %{$config{ENV}}) {
}
$config{wikistatedir}="$config{srcdir}/.ikiwiki"
- unless exists $config{wikistatedir};
-
- if ($config{rcs}) {
- eval qq{use IkiWiki::Rcs::$config{rcs}};
- if ($@) {
- error("Failed to load RCS module IkiWiki::Rcs::$config{rcs}: $@");
- }
- }
- else {
- require IkiWiki::Rcs::Stub;
- }
+ unless exists $config{wikistatedir} && defined $config{wikistatedir};
- if (exists $config{umask}) {
+ if (defined $config{umask}) {
umask(possibly_foolish_untaint($config{umask}));
}
run_hooks(checkconfig => sub { shift->() });
return 1;
-} #}}}
+}
+
+sub listplugins () {
+ my %ret;
+
+ foreach my $dir (@INC, $config{libdir}) {
+ next unless defined $dir && length $dir;
+ foreach my $file (glob("$dir/IkiWiki/Plugin/*.pm")) {
+ my ($plugin)=$file=~/.*\/(.*)\.pm$/;
+ $ret{$plugin}=1;
+ }
+ }
+ foreach my $dir ($config{libdir}, "$installdir/lib/ikiwiki") {
+ next unless defined $dir && length $dir;
+ foreach my $file (glob("$dir/plugins/*")) {
+ $ret{basename($file)}=1 if -x $file;
+ }
+ }
-sub loadplugins () { #{{{
- if (defined $config{libdir}) {
+ return keys %ret;
+}
+
+sub loadplugins () {
+ if (defined $config{libdir} && length $config{libdir}) {
unshift @INC, possibly_foolish_untaint($config{libdir});
}
- loadplugin($_) foreach @{$config{plugin}};
+ foreach my $plugin (@{$config{default_plugins}}, @{$config{add_plugins}}) {
+ loadplugin($plugin);
+ }
+
+ if ($config{rcs}) {
+ if (exists $IkiWiki::hooks{rcs}) {
+ error(gettext("cannot use multiple rcs plugins"));
+ }
+ loadplugin($config{rcs});
+ }
+ if (! exists $IkiWiki::hooks{rcs}) {
+ loadplugin("norcs");
+ }
run_hooks(getopt => sub { shift->() });
if (grep /^-/, @ARGV) {
- print STDERR "Unknown option: $_\n"
+ print STDERR "Unknown option (or missing parameter): $_\n"
foreach grep /^-/, @ARGV;
usage();
}
return 1;
-} #}}}
+}
-sub loadplugin ($) { #{{{
+sub loadplugin ($) {
my $plugin=shift;
return if grep { $_ eq $plugin} @{$config{disable_plugins}};
foreach my $dir (defined $config{libdir} ? possibly_foolish_untaint($config{libdir}) : undef,
"$installdir/lib/ikiwiki") {
if (defined $dir && -x "$dir/plugins/$plugin") {
- require IkiWiki::Plugin::external;
+ eval { require IkiWiki::Plugin::external };
+ if ($@) {
+ my $reason=$@;
+ error(sprintf(gettext("failed to load external plugin needed for %s plugin: %s"), $plugin, $reason));
+ }
import IkiWiki::Plugin::external "$dir/plugins/$plugin";
+ $loaded_plugins{$plugin}=1;
return 1;
}
}
if ($@) {
error("Failed to load plugin $mod: $@");
}
+ $loaded_plugins{$plugin}=1;
return 1;
-} #}}}
+}
-sub error ($;$) { #{{{
+sub error ($;$) {
my $message=shift;
my $cleaner=shift;
- if ($config{cgi}) {
- print "Content-type: text/html\n\n";
- print misctemplate(gettext("Error"),
- "<p>".gettext("Error").": $message</p>");
- }
log_message('err' => $message) if $config{syslog};
if (defined $cleaner) {
$cleaner->();
}
die $message."\n";
-} #}}}
+}
-sub debug ($) { #{{{
+sub debug ($) {
return unless $config{verbose};
return log_message(debug => @_);
-} #}}}
+}
my $log_open=0;
-sub log_message ($$) { #{{{
+sub log_message ($$) {
my $type=shift;
if ($config{syslog}) {
else {
return print STDERR "@_\n";
}
-} #}}}
+}
-sub possibly_foolish_untaint ($) { #{{{
+sub possibly_foolish_untaint ($) {
my $tainted=shift;
my ($untainted)=$tainted=~/(.*)/s;
return $untainted;
-} #}}}
+}
-sub basename ($) { #{{{
+sub basename ($) {
my $file=shift;
$file=~s!.*/+!!;
return $file;
-} #}}}
+}
-sub dirname ($) { #{{{
+sub dirname ($) {
my $file=shift;
$file=~s!/*[^/]+$!!;
return $file;
-} #}}}
+}
-sub pagetype ($) { #{{{
+sub isinternal ($) {
my $page=shift;
+ return exists $pagesources{$page} &&
+ $pagesources{$page} =~ /\._([^.]+)$/;
+}
+
+sub pagetype ($) {
+ my $file=shift;
- if ($page =~ /\.([^.]+)$/) {
+ if ($file =~ /\.([^.]+)$/) {
return $1 if exists $hooks{htmlize}{$1};
}
+ my $base=basename($file);
+ if (exists $hooks{htmlize}{$base} &&
+ $hooks{htmlize}{$base}{noextension}) {
+ return $base;
+ }
return;
-} #}}}
+}
-sub isinternal ($) { #{{{
- my $page=shift;
- return exists $pagesources{$page} &&
- $pagesources{$page} =~ /\._([^.]+)$/;
-} #}}}
+my %pagename_cache;
-sub pagename ($) { #{{{
+sub pagename ($) {
my $file=shift;
+ if (exists $pagename_cache{$file}) {
+ return $pagename_cache{$file};
+ }
+
my $type=pagetype($file);
my $page=$file;
- $page=~s/\Q.$type\E*$// if defined $type;
+ $page=~s/\Q.$type\E*$//
+ if defined $type && !$hooks{htmlize}{$type}{keepextension}
+ && !$hooks{htmlize}{$type}{noextension};
+ if ($config{indexpages} && $page=~/(.*)\/index$/) {
+ $page=$1;
+ }
+
+ $pagename_cache{$file} = $page;
return $page;
-} #}}}
+}
+
+sub newpagefile ($$) {
+ my $page=shift;
+ my $type=shift;
+
+ if (! $config{indexpages} || $page eq 'index') {
+ return $page.".".$type;
+ }
+ else {
+ return $page."/index.".$type;
+ }
+}
-sub targetpage ($$) { #{{{
+sub targetpage ($$;$) {
my $page=shift;
my $ext=shift;
+ my $filename=shift;
- if (! $config{usedirs} || $page =~ /^index$/ ) {
+ if (defined $filename) {
+ return $page."/".$filename.".".$ext;
+ }
+ elsif (! $config{usedirs} || $page eq 'index') {
return $page.".".$ext;
- } else {
+ }
+ else {
return $page."/index.".$ext;
}
-} #}}}
+}
-sub htmlpage ($) { #{{{
+sub htmlpage ($) {
my $page=shift;
return targetpage($page, $config{htmlext});
-} #}}}
+}
-sub srcfile_stat { #{{{
+sub srcfile_stat {
my $file=shift;
my $nothrow=shift;
}
error("internal error: $file cannot be found in $config{srcdir} or underlay") unless $nothrow;
return;
-} #}}}
+}
-sub srcfile ($;$) { #{{{
+sub srcfile ($;$) {
return (srcfile_stat(@_))[0];
-} #}}}
+}
-sub add_underlay ($) { #{{{
+sub add_underlay ($) {
my $dir=shift;
- if ($dir=~/^\//) {
- unshift @{$config{underlaydirs}}, $dir;
+ if ($dir !~ /^\//) {
+ $dir="$config{underlaydirbase}/$dir";
}
- else {
- unshift @{$config{underlaydirs}}, "$config{underlaydir}/../$dir";
+
+ if (! grep { $_ eq $dir } @{$config{underlaydirs}}) {
+ unshift @{$config{underlaydirs}}, $dir;
}
return 1;
-} #}}}
+}
-sub readfile ($;$$) { #{{{
+sub readfile ($;$$) {
my $file=shift;
my $binary=shift;
my $wantfd=shift;
binmode($in) if ($binary);
return \*$in if $wantfd;
my $ret=<$in>;
+ # check for invalid utf-8, and toss it back to avoid crashes
+ if (! utf8::valid($ret)) {
+ $ret=encode_utf8($ret);
+ }
close $in || error("failed to read $file: $!");
return $ret;
-} #}}}
+}
sub prep_writefile ($$) {
my $file=shift;
return 1;
}
-sub writefile ($$$;$$) { #{{{
+sub writefile ($$$;$$) {
my $file=shift; # can include subdirs
my $destdir=shift; # directory to put file in
my $content=shift;
error("failed renaming $newfile to $destdir/$file: $!", $cleanup);
return 1;
-} #}}}
+}
my %cleared;
-sub will_render ($$;$) { #{{{
+sub will_render ($$;$) {
my $page=shift;
my $dest=shift;
my $clear=shift;
# Important security check.
if (-e "$config{destdir}/$dest" && ! $config{rebuild} &&
- ! grep { $_ eq $dest } (@{$renderedfiles{$page}}, @{$oldrenderedfiles{$page}})) {
+ ! grep { $_ eq $dest } (@{$renderedfiles{$page}}, @{$oldrenderedfiles{$page}}, @{$wikistate{editpage}{previews}})) {
error("$config{destdir}/$dest independently created, not overwriting with version from $page");
}
$destsources{$dest}=$page;
return 1;
-} #}}}
+}
-sub bestlink ($$) { #{{{
+sub bestlink ($$) {
my $page=shift;
my $link=shift;
elsif (exists $pagecase{lc $l}) {
return $pagecase{lc $l};
}
- } while $cwd=~s!/?[^/]+$!!;
+ } while $cwd=~s{/?[^/]+$}{};
if (length $config{userdir}) {
my $l = "$config{userdir}/".lc($link);
#print STDERR "warning: page $page, broken link: $link\n";
return "";
-} #}}}
+}
-sub isinlinableimage ($) { #{{{
+sub isinlinableimage ($) {
my $file=shift;
return $file =~ /\.(png|gif|jpg|jpeg)$/i;
-} #}}}
+}
-sub pagetitle ($;$) { #{{{
+sub pagetitle ($;$) {
my $page=shift;
my $unescaped=shift;
}
return $page;
-} #}}}
+}
-sub titlepage ($) { #{{{
+sub titlepage ($) {
my $title=shift;
- $title=~s/([^-[:alnum:]:+\/.])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
+ # support use w/o %config set
+ my $chars = defined $config{wiki_file_chars} ? $config{wiki_file_chars} : "-[:alnum:]+/.:_";
+ $title=~s/([^$chars]|_)/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
return $title;
-} #}}}
+}
-sub linkpage ($) { #{{{
+sub linkpage ($) {
my $link=shift;
- $link=~s/([^-[:alnum:]:+\/._])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
+ my $chars = defined $config{wiki_file_chars} ? $config{wiki_file_chars} : "-[:alnum:]+/.:_";
+ $link=~s/([^$chars])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
return $link;
-} #}}}
+}
-sub cgiurl (@) { #{{{
+sub cgiurl (@) {
my %params=@_;
return $config{cgiurl}."?".
join("&", map $_."=".uri_escape_utf8($params{$_}), keys %params);
-} #}}}
+}
-sub baseurl (;$) { #{{{
+sub baseurl (;$) {
my $page=shift;
return "$config{url}/" if ! defined $page;
$page=~s/[^\/]+$//;
$page=~s/[^\/]+\//..\//g;
return $page;
-} #}}}
+}
-sub abs2rel ($$) { #{{{
+sub abs2rel ($$) {
# Work around very innefficient behavior in File::Spec if abs2rel
# is passed two relative paths. It's much faster if paths are
# absolute! (Debian bug #376658; fixed in debian unstable now)
my $ret=File::Spec->abs2rel($path, $base);
$ret=~s/^// if defined $ret;
return $ret;
-} #}}}
+}
+
+sub displaytime ($;$) {
+ # Plugins can override this function to mark up the time to
+ # display.
+ return '<span class="date">'.formattime(@_).'</span>';
+}
-sub displaytime ($;$) { #{{{
+sub formattime ($;$) {
+ # Plugins can override this function to format the time.
my $time=shift;
my $format=shift;
if (! defined $format) {
# strftime doesn't know about encodings, so make sure
# its output is properly treated as utf8
return decode_utf8(POSIX::strftime($format, localtime($time)));
-} #}}}
+}
-sub beautify_url ($) { #{{{
+sub beautify_urlpath ($) {
my $url=shift;
+ # Ensure url is not an empty link, and if necessary,
+ # add ./ to avoid colon confusion.
+ if ($url !~ /^\// && $url !~ /^\.\.?\//) {
+ $url="./$url";
+ }
+
if ($config{usedirs}) {
$url =~ s!/index.$config{htmlext}$!/!;
}
- $url =~ s!^$!./!; # Browsers don't like empty links...
return $url;
-} #}}}
+}
-sub urlto ($$) { #{{{
+sub urlto ($$;$) {
my $to=shift;
my $from=shift;
-
+ my $absolute=shift;
+
if (! length $to) {
- return beautify_url(baseurl($from)."index.$config{htmlext}");
+ return beautify_urlpath(baseurl($from)."index.$config{htmlext}");
}
if (! $destsources{$to}) {
$to=htmlpage($to);
}
+ if ($absolute) {
+ return $config{url}.beautify_urlpath("/".$to);
+ }
+
my $link = abs2rel($to, dirname(htmlpage($from)));
- return beautify_url($link);
-} #}}}
+ return beautify_urlpath($link);
+}
-sub htmllink ($$$;@) { #{{{
+sub htmllink ($$$;@) {
my $lpage=shift; # the page doing the linking
my $page=shift; # the page that will contain the link (different for inline)
my $link=shift;
}
$bestlink=abs2rel($bestlink, dirname(htmlpage($page)));
- $bestlink=beautify_url($bestlink);
+ $bestlink=beautify_urlpath($bestlink);
if (! $opts{noimageinline} && isinlinableimage($bestlink)) {
return "<img src=\"$bestlink\" alt=\"$linktext\" />";
}
return "<a href=\"$bestlink\"@attrs>$linktext</a>";
-} #}}}
+}
-sub userlink ($) { #{{{
+sub openiduser ($) {
+ my $user=shift;
+
+ if ($user =~ m!^https?://! &&
+ eval q{use Net::OpenID::VerifiedIdentity; 1} && !$@) {
+ my $display;
+
+ if (Net::OpenID::VerifiedIdentity->can("DisplayOfURL")) {
+ # this works in at least 2.x
+ $display = Net::OpenID::VerifiedIdentity::DisplayOfURL($user);
+ }
+ else {
+ # this only works in 1.x
+ my $oid=Net::OpenID::VerifiedIdentity->new(identity => $user);
+ $display=$oid->display;
+ }
+
+ # Convert "user.somehost.com" to "user [somehost.com]"
+ # (also "user.somehost.co.uk")
+ if ($display !~ /\[/) {
+ $display=~s/^([-a-zA-Z0-9]+?)\.([-.a-zA-Z0-9]+\.[a-z]+)$/$1 [$2]/;
+ }
+ # Convert "http://somehost.com/user" to "user [somehost.com]".
+ # (also "https://somehost.com/user/")
+ if ($display !~ /\[/) {
+ $display=~s/^https?:\/\/(.+)\/([^\/]+)\/?$/$2 [$1]/;
+ }
+ $display=~s!^https?://!!; # make sure this is removed
+ eval q{use CGI 'escapeHTML'};
+ error($@) if $@;
+ return escapeHTML($display);
+ }
+ return;
+}
+
+sub userlink ($) {
my $user=shift;
my $oiduser=eval { openiduser($user) };
length $config{userdir} ? $config{userdir}."/".$user : $user
), noimageinline => 1);
}
-} #}}}
+}
-sub htmlize ($$$$) { #{{{
+sub htmlize ($$$$) {
my $page=shift;
my $destpage=shift;
my $type=shift;
}
return $content;
-} #}}}
+}
-sub linkify ($$$) { #{{{
+sub linkify ($$$) {
my $page=shift;
my $destpage=shift;
my $content=shift;
});
return $content;
-} #}}}
+}
our %preprocessing;
our $preprocess_preview=0;
-sub preprocess ($$$;$$) { #{{{
+sub preprocess ($$$;$$) {
my $page=shift; # the page the data comes from
my $destpage=shift; # the page the data will appear in (different for inline)
my $content=shift;
my $prefix=shift;
my $command=shift;
my $params=shift;
+ $params="" if ! defined $params;
+
if (length $escape) {
return "[[$prefix$command $params]]";
}
if ($preprocessing{$page}++ > 3) {
# Avoid loops of preprocessed pages preprocessing
# other pages that preprocess them, etc.
- #translators: The first parameter is a
- #translators: preprocessor directive name,
- #translators: the second a page name, the
- #translators: third a number.
- return "[[".sprintf(gettext("%s preprocessing loop detected on %s at depth %i"),
- $command, $page, $preprocessing{$page}).
- "]]";
+ return "[[!$command <span class=\"error\">".
+ sprintf(gettext("preprocessing loop detected on %s at depth %i"),
+ $page, $preprocessing{$page}).
+ "</span>]]";
}
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 ($@) {
+ my $error=$@;
+ chomp $error;
+ $ret="[[!$command <span class=\"error\">".
+ gettext("Error").": $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}--;
|
"[^"]+" # single-quoted value
|
- [^\s\]]+ # unquoted value
+ [^"\s\]]+ # unquoted value
)
\s* # whitespace or end
# of directive
*)? # 0 or more parameters
\]\] # directive closed
}sx;
- } else {
+ }
+ else {
$regex = qr{
(\\?) # 1: escape?
\[\[(!?) # directive open; 2: optional prefix
|
"[^"]+" # single-quoted value
|
- [^\s\]]+ # unquoted value
+ [^"\s\]]+ # unquoted value
)
\s* # whitespace or end
# of directive
$content =~ s{$regex}{$handle->($1, $2, $3, $4)}eg;
return $content;
-} #}}}
+}
-sub filter ($$$) { #{{{
+sub filter ($$$) {
my $page=shift;
my $destpage=shift;
my $content=shift;
});
return $content;
-} #}}}
+}
-sub indexlink () { #{{{
+sub indexlink () {
return "<a href=\"$config{url}\">$config{wikiname}</a>";
-} #}}}
+}
+
+sub check_canedit ($$$;$) {
+ my $page=shift;
+ my $q=shift;
+ my $session=shift;
+ my $nonfatal=shift;
+
+ my $canedit;
+ run_hooks(canedit => sub {
+ return if defined $canedit;
+ my $ret=shift->($page, $q, $session);
+ if (defined $ret) {
+ if ($ret eq "") {
+ $canedit=1;
+ }
+ elsif (ref $ret eq 'CODE') {
+ $ret->() unless $nonfatal;
+ $canedit=0;
+ }
+ elsif (defined $ret) {
+ error($ret) unless $nonfatal;
+ $canedit=0;
+ }
+ }
+ });
+ return defined $canedit ? $canedit : 1;
+}
+
+sub check_content (@) {
+ my %params=@_;
+
+ return 1 if ! exists $hooks{checkcontent}; # optimisation
+
+ if (exists $pagesources{$params{page}}) {
+ my @diff;
+ my %old=map { $_ => 1 }
+ split("\n", readfile(srcfile($pagesources{$params{page}})));
+ foreach my $line (split("\n", $params{content})) {
+ push @diff, $line if ! exists $old{$_};
+ }
+ $params{diff}=join("\n", @diff);
+ }
+
+ my $ok;
+ run_hooks(checkcontent => sub {
+ return if defined $ok;
+ my $ret=shift->(%params);
+ if (defined $ret) {
+ if ($ret eq "") {
+ $ok=1;
+ }
+ elsif (ref $ret eq 'CODE') {
+ $ret->() unless $params{nonfatal};
+ $ok=0;
+ }
+ elsif (defined $ret) {
+ error($ret) unless $params{nonfatal};
+ $ok=0;
+ }
+ }
+
+ });
+ return defined $ok ? $ok : 1;
+}
my $wikilock;
-sub lockwiki (;$) { #{{{
- my $wait=@_ ? shift : 1;
+sub lockwiki () {
# Take an exclusive lock on the wiki to prevent multiple concurrent
# run issues. The lock will be dropped on program exit.
if (! -d $config{wikistatedir}) {
}
open($wikilock, '>', "$config{wikistatedir}/lockfile") ||
error ("cannot write to $config{wikistatedir}/lockfile: $!");
- if (! flock($wikilock, 2 | 4)) { # LOCK_EX | LOCK_NB
- if ($wait) {
- debug("wiki seems to be locked, waiting for lock");
- my $wait=600; # arbitrary, but don't hang forever to
- # prevent process pileup
- for (1..$wait) {
- return if flock($wikilock, 2 | 4);
- sleep 1;
- }
- error("wiki is locked; waited $wait seconds without lock being freed (possible stuck process or stale lock?)");
- }
- else {
- return 0;
- }
+ if (! flock($wikilock, 2)) { # LOCK_EX
+ error("failed to get lock");
}
return 1;
-} #}}}
+}
-sub unlockwiki () { #{{{
+sub unlockwiki () {
+ POSIX::close($ENV{IKIWIKI_CGILOCK_FD}) if exists $ENV{IKIWIKI_CGILOCK_FD};
return close($wikilock) if $wikilock;
return;
-} #}}}
+}
my $commitlock;
-sub commit_hook_enabled () { #{{{
+sub commit_hook_enabled () {
open($commitlock, '+>', "$config{wikistatedir}/commitlock") ||
error("cannot write to $config{wikistatedir}/commitlock: $!");
if (! flock($commitlock, 1 | 4)) { # LOCK_SH | LOCK_NB to test
}
close($commitlock) || error("failed closing commitlock: $!");
return 1;
-} #}}}
+}
-sub disable_commit_hook () { #{{{
+sub disable_commit_hook () {
open($commitlock, '>', "$config{wikistatedir}/commitlock") ||
error("cannot write to $config{wikistatedir}/commitlock: $!");
if (! flock($commitlock, 2)) { # LOCK_EX
error("failed to get commit lock");
}
return 1;
-} #}}}
+}
-sub enable_commit_hook () { #{{{
+sub enable_commit_hook () {
return close($commitlock) if $commitlock;
return;
-} #}}}
+}
-sub loadindex () { #{{{
+sub loadindex () {
%oldrenderedfiles=%pagectime=();
if (! $config{rebuild}) {
%pagesources=%pagemtime=%oldlinks=%links=%depends=
return;
}
}
- my $ret=Storable::fd_retrieve($in);
- if (! defined $ret) {
+
+ my $index=Storable::fd_retrieve($in);
+ if (! defined $index) {
return 0;
}
- my %index=%$ret;
- foreach my $src (keys %index) {
- my %d=%{$index{$src}};
+
+ my $pages;
+ if (exists $index->{version} && ! ref $index->{version}) {
+ $pages=$index->{page};
+ %wikistate=%{$index->{state}};
+ }
+ else {
+ $pages=$index;
+ %wikistate=();
+ }
+
+ foreach my $src (keys %$pages) {
+ my $d=$pages->{$src};
my $page=pagename($src);
- $pagectime{$page}=$d{ctime};
+ $pagectime{$page}=$d->{ctime};
if (! $config{rebuild}) {
$pagesources{$page}=$src;
- $pagemtime{$page}=$d{mtime};
- $renderedfiles{$page}=$d{dest};
- if (exists $d{links} && ref $d{links}) {
- $links{$page}=$d{links};
- $oldlinks{$page}=[@{$d{links}}];
+ $pagemtime{$page}=$d->{mtime};
+ $renderedfiles{$page}=$d->{dest};
+ if (exists $d->{links} && ref $d->{links}) {
+ $links{$page}=$d->{links};
+ $oldlinks{$page}=[@{$d->{links}}];
+ }
+ if (exists $d->{dependslist}) {
+ $depends{$page}={
+ map { $_ => 1 } @{$d->{dependslist}}
+ };
}
- if (exists $d{depends}) {
- $depends{$page}=$d{depends};
+ elsif (exists $d->{depends}) {
+ $depends{$page}={$d->{depends} => 1};
}
- if (exists $d{state}) {
- $pagestate{$page}=$d{state};
+ if (exists $d->{state}) {
+ $pagestate{$page}=$d->{state};
}
}
- $oldrenderedfiles{$page}=[@{$d{dest}}];
+ $oldrenderedfiles{$page}=[@{$d->{dest}}];
}
foreach my $page (keys %pagesources) {
$pagecase{lc $page}=$page;
$destsources{$_}=$page foreach @{$renderedfiles{$page}};
}
return close($in);
-} #}}}
+}
-sub saveindex () { #{{{
+sub saveindex () {
run_hooks(savestate => sub { shift->() });
my %hookids;
my $newfile="$config{wikistatedir}/indexdb.new";
my $cleanup = sub { unlink($newfile) };
open (my $out, '>', $newfile) || error("cannot write to $newfile: $!", $cleanup);
+
my %index;
foreach my $page (keys %pagemtime) {
next unless $pagemtime{$page};
my $src=$pagesources{$page};
- $index{$src}={
+ $index{page}{$src}={
ctime => $pagectime{$page},
mtime => $pagemtime{$page},
dest => $renderedfiles{$page},
};
if (exists $depends{$page}) {
- $index{$src}{depends} = $depends{$page};
+ $index{page}{$src}{dependslist} = [ keys %{$depends{$page}} ];
}
if (exists $pagestate{$page}) {
foreach my $id (@hookids) {
foreach my $key (keys %{$pagestate{$page}{$id}}) {
- $index{$src}{state}{$id}{$key}=$pagestate{$page}{$id}{$key};
+ $index{page}{$src}{state}{$id}{$key}=$pagestate{$page}{$id}{$key};
}
}
}
}
+
+ $index{state}={};
+ foreach my $id (@hookids) {
+ foreach my $key (keys %{$wikistate{$id}}) {
+ $index{state}{$id}{$key}=$wikistate{$id}{$key};
+ }
+ }
+
+ $index{version}="3";
my $ret=Storable::nstore_fd(\%index, $out);
return if ! defined $ret || ! $ret;
close $out || error("failed saving to $newfile: $!", $cleanup);
error("failed renaming $newfile to $config{wikistatedir}/indexdb", $cleanup);
return 1;
-} #}}}
+}
-sub template_file ($) { #{{{
+sub template_file ($) {
my $template=shift;
foreach my $dir ($config{templatedir}, "$installdir/share/ikiwiki/templates") {
return "$dir/$template" if -e "$dir/$template";
}
return;
-} #}}}
+}
-sub template_params (@) { #{{{
+sub template_params (@) {
my $filename=template_file(shift);
if (! defined $filename) {
@_
);
return wantarray ? @ret : {@ret};
-} #}}}
+}
-sub template ($;@) { #{{{
+sub template ($;@) {
require HTML::Template;
return HTML::Template->new(template_params(@_));
-} #}}}
+}
-sub misctemplate ($$;@) { #{{{
+sub misctemplate ($$;@) {
my $title=shift;
my $pagebody=shift;
shift->(page => "", destpage => "", template => $template);
});
return $template->output;
-}#}}}
+}
-sub hook (@) { # {{{
+sub hook (@) {
my %param=@_;
if (! exists $param{type} || ! ref $param{call} || ! exists $param{id}) {
$hooks{$param{type}}{$param{id}}=\%param;
return 1;
-} # }}}
+}
-sub run_hooks ($$) { # {{{
+sub run_hooks ($$) {
# Calls the given sub for each hook of the given type,
# passing it the hook function to call.
my $type=shift;
my $sub=shift;
if (exists $hooks{$type}) {
- my @deferred;
+ my (@first, @middle, @last);
foreach my $id (keys %{$hooks{$type}}) {
- if ($hooks{$type}{$id}{last}) {
- push @deferred, $id;
- next;
+ if ($hooks{$type}{$id}{first}) {
+ push @first, $id;
+ }
+ elsif ($hooks{$type}{$id}{last}) {
+ push @last, $id;
+ }
+ else {
+ push @middle, $id;
}
- $sub->($hooks{$type}{$id}{call});
}
- foreach my $id (@deferred) {
+ foreach my $id (@first, @middle, @last) {
$sub->($hooks{$type}{$id}{call});
}
}
return 1;
-} #}}}
+}
-sub globlist_to_pagespec ($) { #{{{
- my @globlist=split(' ', shift);
+sub rcs_update () {
+ $hooks{rcs}{rcs_update}{call}->(@_);
+}
- my (@spec, @skip);
- foreach my $glob (@globlist) {
- if ($glob=~/^!(.*)/) {
- push @skip, $glob;
- }
- else {
- push @spec, $glob;
- }
- }
+sub rcs_prepedit ($) {
+ $hooks{rcs}{rcs_prepedit}{call}->(@_);
+}
- my $spec=join(' or ', @spec);
- if (@skip) {
- my $skip=join(' and ', @skip);
- if (length $spec) {
- $spec="$skip and ($spec)";
- }
- else {
- $spec=$skip;
- }
- }
- return $spec;
-} #}}}
+sub rcs_commit ($$$;$$) {
+ $hooks{rcs}{rcs_commit}{call}->(@_);
+}
-sub is_globlist ($) { #{{{
- my $s=shift;
- return ( $s =~ /[^\s]+\s+([^\s]+)/ && $1 ne "and" && $1 ne "or" );
-} #}}}
+sub rcs_commit_staged ($$$) {
+ $hooks{rcs}{rcs_commit_staged}{call}->(@_);
+}
+
+sub rcs_add ($) {
+ $hooks{rcs}{rcs_add}{call}->(@_);
+}
-sub safequote ($) { #{{{
- my $s=shift;
- $s=~s/[{}]//g;
- return "q{$s}";
-} #}}}
+sub rcs_remove ($) {
+ $hooks{rcs}{rcs_remove}{call}->(@_);
+}
-sub add_depends ($$) { #{{{
+sub rcs_rename ($$) {
+ $hooks{rcs}{rcs_rename}{call}->(@_);
+}
+
+sub rcs_recentchanges ($) {
+ $hooks{rcs}{rcs_recentchanges}{call}->(@_);
+}
+
+sub rcs_diff ($) {
+ $hooks{rcs}{rcs_diff}{call}->(@_);
+}
+
+sub rcs_getctime ($) {
+ $hooks{rcs}{rcs_getctime}{call}->(@_);
+}
+
+sub rcs_receive () {
+ $hooks{rcs}{rcs_receive}{call}->();
+}
+
+sub add_depends ($$) {
my $page=shift;
my $pagespec=shift;
-
- return unless pagespec_valid($pagespec);
- if (! exists $depends{$page}) {
- $depends{$page}=$pagespec;
- }
- else {
- $depends{$page}=pagespec_merge($depends{$page}, $pagespec);
- }
+ return unless pagespec_valid($pagespec);
+ $depends{$page}{$pagespec} = 1;
return 1;
-} # }}}
+}
-sub file_pruned ($$) { #{{{
+sub file_pruned ($$) {
require File::Spec;
my $file=File::Spec->canonpath(shift);
my $base=File::Spec->canonpath(shift);
my $regexp='('.join('|', @{$config{wiki_file_prune_regexps}}).')';
return $file =~ m/$regexp/ && $file ne $base;
-} #}}}
+}
-sub gettext { #{{{
- # Only use gettext in the rare cases it's needed.
+sub define_gettext () {
+ # If translation is needed, redefine the gettext function to do it.
+ # Otherwise, it becomes a quick no-op.
+ no warnings 'redefine';
if ((exists $ENV{LANG} && length $ENV{LANG}) ||
(exists $ENV{LC_ALL} && length $ENV{LC_ALL}) ||
(exists $ENV{LC_MESSAGES} && length $ENV{LC_MESSAGES})) {
- if (! $gettext_obj) {
- $gettext_obj=eval q{
+ *gettext=sub {
+ my $gettext_obj=eval q{
use Locale::gettext q{textdomain};
Locale::gettext->domain('ikiwiki')
};
- if ($@) {
- print STDERR "$@";
- $gettext_obj=undef;
+
+ if ($gettext_obj) {
+ $gettext_obj->get(shift);
+ }
+ else {
return shift;
}
- }
- return $gettext_obj->get(shift);
+ };
}
else {
- return shift;
+ *gettext=sub { return shift };
}
-} #}}}
+}
-sub pagespec_merge ($$) { #{{{
- my $a=shift;
- my $b=shift;
+sub gettext {
+ define_gettext();
+ gettext(@_);
+}
- return $a if $a eq $b;
+sub yesno ($) {
+ my $val=shift;
- # Support for old-style GlobLists.
- if (is_globlist($a)) {
- $a=globlist_to_pagespec($a);
- }
- if (is_globlist($b)) {
- $b=globlist_to_pagespec($b);
- }
+ return (defined $val && (lc($val) eq gettext("yes") || lc($val) eq "yes" || $val eq "1"));
+}
- return "($a) or ($b)";
-} #}}}
+sub inject {
+ # Injects a new function into the symbol table to replace an
+ # exported function.
+ my %params=@_;
-sub pagespec_translate ($) { #{{{
- my $spec=shift;
+ # This is deep ugly perl foo, beware.
+ no strict;
+ no warnings;
+ if (! defined $params{parent}) {
+ $params{parent}='::';
+ $params{old}=\&{$params{name}};
+ $params{name}=~s/.*:://;
+ }
+ my $parent=$params{parent};
+ foreach my $ns (grep /^\w+::/, keys %{$parent}) {
+ $ns = $params{parent} . $ns;
+ inject(%params, parent => $ns) unless $ns eq '::main::';
+ *{$ns . $params{name}} = $params{call}
+ if exists ${$ns}{$params{name}} &&
+ \&{${$ns}{$params{name}}} == $params{old};
+ }
+ use strict;
+ use warnings;
+}
- # Support for old-style GlobLists.
- if (is_globlist($spec)) {
- $spec=globlist_to_pagespec($spec);
- }
+sub add_link ($$) {
+ my $page=shift;
+ my $link=shift;
+
+ push @{$links{$page}}, $link
+ unless grep { $_ eq $link } @{$links{$page}};
+}
+
+sub pagespec_translate ($) {
+ my $spec=shift;
# Convert spec to perl code.
my $code="";
+ my @data;
while ($spec=~m{
\s* # ignore whitespace
( # 1: match a single word
}
elsif ($word =~ /^(\w+)\((.*)\)$/) {
if (exists $IkiWiki::PageSpec::{"match_$1"}) {
- $code.="IkiWiki::PageSpec::match_$1(\$page, ".safequote($2).", \@_)";
+ push @data, $2;
+ $code.="IkiWiki::PageSpec::match_$1(\$page, \$data[$#data], \@_)";
}
else {
- $code.=' 0';
+ push @data, qq{unknown function in pagespec "$word"};
+ $code.="IkiWiki::ErrorReason->new(\$data[$#data])";
}
}
else {
- $code.=" IkiWiki::PageSpec::match_glob(\$page, ".safequote($word).", \@_)";
+ push @data, $word;
+ $code.=" IkiWiki::PageSpec::match_glob(\$page, \$data[$#data], \@_)";
}
}
if (! length $code) {
- $code=0;
+ $code="IkiWiki::FailReason->new('empty pagespec')";
}
no warnings;
return eval 'sub { my $page=shift; '.$code.' }';
-} #}}}
+}
-sub pagespec_match ($$;@) { #{{{
+sub pagespec_match ($$;@) {
my $page=shift;
my $spec=shift;
my @params=@_;
}
my $sub=pagespec_translate($spec);
- return IkiWiki::FailReason->new("syntax error in pagespec \"$spec\"") if $@;
+ return IkiWiki::ErrorReason->new("syntax error in pagespec \"$spec\"")
+ if $@ || ! defined $sub;
return $sub->($page, @params);
-} #}}}
+}
-sub pagespec_valid ($) { #{{{
+sub pagespec_match_list ($$;@) {
+ my $pages=shift;
my $spec=shift;
+ my @params=@_;
my $sub=pagespec_translate($spec);
- return ! $@;
-} #}}}
+ error "syntax error in pagespec \"$spec\""
+ if $@ || ! defined $sub;
-sub glob2re ($) { #{{{
+ my @ret;
+ my $r;
+ foreach my $page (@$pages) {
+ $r=$sub->($page, @params);
+ push @ret, $page if $r;
+ }
+
+ if (! @ret && defined $r && $r->isa("IkiWiki::ErrorReason")) {
+ error(sprintf(gettext("cannot match pages: %s"), $r));
+ }
+ else {
+ return @ret;
+ }
+}
+
+sub pagespec_valid ($) {
+ my $spec=shift;
+
+ my $sub=pagespec_translate($spec);
+ return ! $@;
+}
+
+sub glob2re ($) {
my $re=quotemeta(shift);
$re=~s/\\\*/.*/g;
$re=~s/\\\?/./g;
return $re;
-} #}}}
+}
package IkiWiki::FailReason;
-use overload ( #{{{
+use overload (
'""' => sub { ${$_[0]} },
'0+' => sub { 0 },
'!' => sub { bless $_[0], 'IkiWiki::SuccessReason'},
fallback => 1,
-); #}}}
+);
-sub new { #{{{
+sub new {
my $class = shift;
my $value = shift;
return bless \$value, $class;
-} #}}}
+}
+
+package IkiWiki::ErrorReason;
+
+our @ISA = 'IkiWiki::FailReason';
package IkiWiki::SuccessReason;
-use overload ( #{{{
+use overload (
'""' => sub { ${$_[0]} },
'0+' => sub { 1 },
'!' => sub { bless $_[0], 'IkiWiki::FailReason'},
fallback => 1,
-); #}}}
+);
-sub new { #{{{
+sub new {
my $class = shift;
my $value = shift;
return bless \$value, $class;
-}; #}}}
+};
package IkiWiki::PageSpec;
-sub match_glob ($$;@) { #{{{
+sub derel ($$) {
+ my $path=shift;
+ my $from=shift;
+
+ if ($path =~ m!^\./!) {
+ $from=~s#/?[^/]+$## if defined $from;
+ $path=~s#^\./##;
+ $path="$from/$path" if length $from;
+ }
+
+ return $path;
+}
+
+sub match_glob ($$;@) {
my $page=shift;
my $glob=shift;
my %params=@_;
- my $from=exists $params{location} ? $params{location} : '';
-
- # relative matching
- if ($glob =~ m!^\./!) {
- $from=~s#/?[^/]+$##;
- $glob=~s#^\./##;
- $glob="$from/$glob" if length $from;
- }
+ $glob=derel($glob, $params{location});
my $regexp=IkiWiki::glob2re($glob);
if ($page=~/^$regexp$/i) {
else {
return IkiWiki::FailReason->new("$glob does not match $page");
}
-} #}}}
+}
-sub match_internal ($$;@) { #{{{
+sub match_internal ($$;@) {
return match_glob($_[0], $_[1], @_, internal => 1)
-} #}}}
+}
-sub match_link ($$;@) { #{{{
+sub match_link ($$;@) {
my $page=shift;
my $link=lc(shift);
my %params=@_;
+ $link=derel($link, $params{location});
my $from=exists $params{location} ? $params{location} : '';
- # relative matching
- if ($link =~ m!^\.! && defined $from) {
- $from=~s#/?[^/]+$##;
- $link=~s#^\./##;
- $link="$from/$link" if length $from;
- }
-
my $links = $IkiWiki::links{$page};
return IkiWiki::FailReason->new("$page has no links") unless $links && @{$links};
my $bestlink = IkiWiki::bestlink($from, $link);
else {
return IkiWiki::SuccessReason->new("$page links to page $p matching $link")
if match_glob($p, $link, %params);
+ $p=~s/^\///;
+ $link=~s/^\///;
+ return IkiWiki::SuccessReason->new("$page links to page $p matching $link")
+ if match_glob($p, $link, %params);
}
}
return IkiWiki::FailReason->new("$page does not link to $link");
-} #}}}
+}
-sub match_backlink ($$;@) { #{{{
+sub match_backlink ($$;@) {
return match_link($_[1], $_[0], @_);
-} #}}}
+}
-sub match_created_before ($$;@) { #{{{
+sub match_created_before ($$;@) {
my $page=shift;
my $testpage=shift;
+ my %params=@_;
+
+ $testpage=derel($testpage, $params{location});
if (exists $IkiWiki::pagectime{$testpage}) {
if ($IkiWiki::pagectime{$page} < $IkiWiki::pagectime{$testpage}) {
}
}
else {
- return IkiWiki::FailReason->new("$testpage has no ctime");
+ return IkiWiki::ErrorReason->new("$testpage does not exist");
}
-} #}}}
+}
-sub match_created_after ($$;@) { #{{{
+sub match_created_after ($$;@) {
my $page=shift;
my $testpage=shift;
+ my %params=@_;
+
+ $testpage=derel($testpage, $params{location});
if (exists $IkiWiki::pagectime{$testpage}) {
if ($IkiWiki::pagectime{$page} > $IkiWiki::pagectime{$testpage}) {
}
}
else {
- return IkiWiki::FailReason->new("$testpage has no ctime");
+ return IkiWiki::ErrorReason->new("$testpage does not exist");
}
-} #}}}
+}
-sub match_creation_day ($$;@) { #{{{
+sub match_creation_day ($$;@) {
if ((gmtime($IkiWiki::pagectime{shift()}))[3] == shift) {
return IkiWiki::SuccessReason->new('creation_day matched');
}
else {
return IkiWiki::FailReason->new('creation_day did not match');
}
-} #}}}
+}
-sub match_creation_month ($$;@) { #{{{
+sub match_creation_month ($$;@) {
if ((gmtime($IkiWiki::pagectime{shift()}))[4] + 1 == shift) {
return IkiWiki::SuccessReason->new('creation_month matched');
}
else {
return IkiWiki::FailReason->new('creation_month did not match');
}
-} #}}}
+}
-sub match_creation_year ($$;@) { #{{{
+sub match_creation_year ($$;@) {
if ((gmtime($IkiWiki::pagectime{shift()}))[5] + 1900 == shift) {
return IkiWiki::SuccessReason->new('creation_year matched');
}
else {
return IkiWiki::FailReason->new('creation_year did not match');
}
-} #}}}
+}
+
+sub match_user ($$;@) {
+ shift;
+ my $user=shift;
+ my %params=@_;
+
+ if (! exists $params{user}) {
+ return IkiWiki::ErrorReason->new("no user specified");
+ }
+
+ if (defined $params{user} && lc $params{user} eq lc $user) {
+ return IkiWiki::SuccessReason->new("user is $user");
+ }
+ elsif (! defined $params{user}) {
+ return IkiWiki::FailReason->new("not logged in");
+ }
+ else {
+ return IkiWiki::FailReason->new("user is $params{user}, not $user");
+ }
+}
+
+sub match_admin ($$;@) {
+ shift;
+ shift;
+ my %params=@_;
+
+ if (! exists $params{user}) {
+ return IkiWiki::ErrorReason->new("no user specified");
+ }
+
+ if (defined $params{user} && IkiWiki::is_admin($params{user})) {
+ return IkiWiki::SuccessReason->new("user is an admin");
+ }
+ elsif (! defined $params{user}) {
+ return IkiWiki::FailReason->new("not logged in");
+ }
+ else {
+ return IkiWiki::FailReason->new("user is not an admin");
+ }
+}
+
+sub match_ip ($$;@) {
+ shift;
+ my $ip=shift;
+ my %params=@_;
+
+ if (! exists $params{ip}) {
+ return IkiWiki::ErrorReason->new("no IP specified");
+ }
+
+ if (defined $params{ip} && lc $params{ip} eq lc $ip) {
+ return IkiWiki::SuccessReason->new("IP is $ip");
+ }
+ else {
+ return IkiWiki::FailReason->new("IP is $params{ip}, not $ip");
+ }
+}
1
#!/usr/bin/perl
+package IkiWiki;
+
use warnings;
use strict;
use IkiWiki;
use open qw{:utf8 :std};
use Encode;
-package IkiWiki;
-
-sub printheader ($) { #{{{
+sub printheader ($) {
my $session=shift;
if ($config{sslcookie}) {
print $session->header(-charset => 'utf-8',
- -cookie => $session->cookie(-secure => 1));
+ -cookie => $session->cookie(-httponly => 1, -secure => 1));
} else {
- print $session->header(-charset => 'utf-8');
+ print $session->header(-charset => 'utf-8',
+ -cookie => $session->cookie(-httponly => 1));
}
+}
-} #}}}
-
-sub showform ($$$$;@) { #{{{
+sub showform ($$$$;@) {
my $form=shift;
my $buttons=shift;
my $session=shift;
print misctemplate($form->title, $form->render(submit => $buttons), @_);
}
-sub redirect ($$) { #{{{
+sub redirect ($$) {
my $q=shift;
my $url=shift;
if (! $config{w3mmode}) {
print "Content-type: text/plain\n";
print "W3m-control: GOTO $url\n\n";
}
-} #}}}
-
-sub check_canedit ($$$;$) { #{{{
- my $page=shift;
- my $q=shift;
- my $session=shift;
- my $nonfatal=shift;
-
- my $canedit;
- run_hooks(canedit => sub {
- return if defined $canedit;
- my $ret=shift->($page, $q, $session);
- if (defined $ret) {
- if ($ret eq "") {
- $canedit=1;
- }
- elsif (ref $ret eq 'CODE') {
- $ret->() unless $nonfatal;
- $canedit=0;
- }
- elsif (defined $ret) {
- error($ret) unless $nonfatal;
- $canedit=0;
- }
- }
- });
- return $canedit;
-} #}}}
+}
-sub decode_cgi_utf8 ($) { #{{{
+sub decode_cgi_utf8 ($) {
# decode_form_utf8 method is needed for 5.10
if ($] < 5.01) {
my $cgi = shift;
$cgi->param($f, map { decode_utf8 $_ } $cgi->param($f));
}
}
-} #}}}
+}
-sub decode_form_utf8 ($) { #{{{
+sub decode_form_utf8 ($) {
if ($] >= 5.01) {
my $form = shift;
foreach my $f ($form->field) {
);
}
}
-} #}}}
+}
# Check if the user is signed in. If not, redirect to the signin form and
# save their place to return to later.
-sub needsignin ($$) { #{{{
+sub needsignin ($$) {
my $q=shift;
my $session=shift;
cgi_savesession($session);
exit;
}
-} #}}}
+}
-sub cgi_signin ($$) { #{{{
+sub cgi_signin ($$) {
my $q=shift;
my $session=shift;
}
showform($form, $buttons, $session, $q);
-} #}}}
+}
-sub cgi_postsignin ($$) { #{{{
+sub cgi_postsignin ($$) {
my $q=shift;
my $session=shift;
exit;
}
else {
- error(gettext("login failed, perhaps you need to turn on cookies?"));
+ if ($config{sslcookie} && ! $q->https()) {
+ error(gettext("probable misconfiguration: sslcookie is set, but you are attempting to login via http, not https"));
+ }
+ else {
+ error(gettext("login failed, perhaps you need to turn on cookies?"));
+ }
}
-} #}}}
+}
-sub cgi_prefs ($$) { #{{{
+sub cgi_prefs ($$) {
my $q=shift;
my $session=shift;
$form->field(name => "sid", type => "hidden", value => $session->id,
force => 1);
$form->field(name => "email", size => 50, fieldset => "preferences");
- $form->field(name => "banned_users", size => 50,
- fieldset => "admin");
my $user_name=$session->param("name");
- if (! is_admin($user_name)) {
- $form->field(name => "banned_users", type => "hidden");
- }
if (! $form->submitted) {
$form->field(name => "email", force => 1,
value => userinfo_get($user_name, "email"));
- if (is_admin($user_name)) {
- $form->field(name => "banned_users", force => 1,
- value => join(" ", get_banned_users()));
- }
}
if ($form->submitted eq 'Logout') {
userinfo_set($user_name, 'email', $form->field('email')) ||
error("failed to set email");
}
- if (is_admin($user_name)) {
- set_banned_users(grep { ! is_admin($_) }
- split(' ',
- $form->field("banned_users"))) ||
- error("failed saving changes");
- }
+
$form->text(gettext("Preferences saved."));
}
showform($form, $buttons, $session, $q);
-} #}}}
-
-sub cgi_editpage ($$) { #{{{
- my $q=shift;
- my $session=shift;
-
- decode_cgi_utf8($q);
-
- my @fields=qw(do rcsinfo subpage from page type editcontent comments);
- my @buttons=("Save Page", "Preview", "Cancel");
- eval q{use CGI::FormBuilder};
- error($@) if $@;
- my $form = CGI::FormBuilder->new(
- fields => \@fields,
- charset => "utf-8",
- method => 'POST',
- required => [qw{editcontent}],
- javascript => 0,
- params => $q,
- action => $config{cgiurl},
- header => 0,
- table => 0,
- template => scalar template_params("editpage.tmpl"),
- wikiname => $config{wikiname},
- );
-
- decode_form_utf8($form);
- run_hooks(formbuilder_setup => sub {
- shift->(form => $form, cgi => $q, session => $session,
- buttons => \@buttons);
- });
- decode_form_utf8($form);
-
- # This untaint is safe because we check file_pruned.
- my $page=$form->field('page');
- $page=possibly_foolish_untaint($page);
- if (! defined $page || ! length $page ||
- file_pruned($page, $config{srcdir}) || $page=~/^\//) {
- error("bad page name");
- }
-
- my $baseurl=$config{url}."/".htmlpage($page);
-
- my $from;
- if (defined $form->field('from')) {
- ($from)=$form->field('from')=~/$config{wiki_file_regexp}/;
- }
-
- my $file;
- my $type;
- if (exists $pagesources{$page} && $form->field("do") ne "create") {
- $file=$pagesources{$page};
- $type=pagetype($file);
- if (! defined $type || $type=~/^_/) {
- error(sprintf(gettext("%s is not an editable page"), $page));
- }
- if (! $form->submitted) {
- $form->field(name => "rcsinfo",
- value => rcs_prepedit($file), force => 1);
- }
- $form->field(name => "editcontent", validate => '/.*/');
- }
- else {
- $type=$form->param('type');
- if (defined $type && length $type && $hooks{htmlize}{$type}) {
- $type=possibly_foolish_untaint($type);
- }
- elsif (defined $from && exists $pagesources{$from}) {
- # favor the type of linking page
- $type=pagetype($pagesources{$from});
- }
- $type=$config{default_pageext} unless defined $type;
- $file=$page.".".$type;
- if (! $form->submitted) {
- $form->field(name => "rcsinfo", value => "", force => 1);
- }
- $form->field(name => "editcontent", validate => '/.+/');
- }
-
- $form->field(name => "do", type => 'hidden');
- $form->field(name => "sid", type => "hidden", value => $session->id,
- force => 1);
- $form->field(name => "from", type => 'hidden');
- $form->field(name => "rcsinfo", type => 'hidden');
- $form->field(name => "subpage", type => 'hidden');
- $form->field(name => "page", value => $page, force => 1);
- $form->field(name => "type", value => $type, force => 1);
- $form->field(name => "comments", type => "text", size => 80);
- $form->field(name => "editcontent", type => "textarea", rows => 20,
- cols => 80);
- $form->tmpl_param("can_commit", $config{rcs});
- $form->tmpl_param("indexlink", indexlink());
- $form->tmpl_param("helponformattinglink",
- htmllink($page, $page, "ikiwiki/formatting",
- noimageinline => 1,
- linktext => "FormattingHelp"));
-
- if ($form->submitted eq "Cancel") {
- if ($form->field("do") eq "create" && defined $from) {
- redirect($q, "$config{url}/".htmlpage($from));
- }
- elsif ($form->field("do") eq "create") {
- redirect($q, $config{url});
- }
- else {
- redirect($q, "$config{url}/".htmlpage($page));
- }
- return;
- }
- elsif ($form->submitted eq "Preview") {
- my $new=not exists $pagesources{$page};
- if ($new) {
- # temporarily record its type
- $pagesources{$page}=$page.".".$type;
- }
+}
- my $content=$form->field('editcontent');
+sub cgi_custom_failure ($$) {
+ my $header=shift;
+ my $message=shift;
- run_hooks(editcontent => sub {
- $content=shift->(
- content => $content,
- page => $page,
- cgi => $q,
- session => $session,
- );
- });
- my $preview=htmlize($page, $page, $type,
- linkify($page, $page,
- preprocess($page, $page,
- filter($page, $page, $content), 0, 1)));
- run_hooks(format => sub {
- $preview=shift->(
- page => $page,
- content => $preview,
- );
- });
- $form->tmpl_param("page_preview", $preview);
-
- if ($new) {
- delete $pagesources{$page};
- }
- # previewing may have created files on disk
- saveindex();
- }
- elsif ($form->submitted eq "Save Page") {
- $form->tmpl_param("page_preview", "");
- }
- $form->tmpl_param("page_conflict", "");
-
- if ($form->submitted ne "Save Page" || ! $form->validate) {
- if ($form->field("do") eq "create") {
- my @page_locs;
- my $best_loc;
- if (! defined $from || ! length $from ||
- $from ne $form->field('from') ||
- file_pruned($from, $config{srcdir}) ||
- $from=~/^\// ||
- $form->submitted eq "Preview") {
- @page_locs=$best_loc=$page;
- }
- else {
- my $dir=$from."/";
- $dir=~s![^/]+/+$!!;
-
- if ((defined $form->field('subpage') && length $form->field('subpage')) ||
- $page eq gettext('discussion')) {
- $best_loc="$from/$page";
- }
- else {
- $best_loc=$dir.$page;
- }
-
- push @page_locs, $dir.$page;
- push @page_locs, "$from/$page";
- while (length $dir) {
- $dir=~s![^/]+/+$!!;
- push @page_locs, $dir.$page;
- }
-
- push @page_locs, "$config{userdir}/$page"
- if length $config{userdir};
- }
+ print $header;
+ print $message;
- @page_locs = grep {
- ! exists $pagecase{lc $_}
- } @page_locs;
- if (! @page_locs) {
- # hmm, someone else made the page in the
- # meantime?
- if ($form->submitted eq "Preview") {
- # let them go ahead with the edit
- # and resolve the conflict at save
- # time
- @page_locs=$page;
- }
- else {
- redirect($q, "$config{url}/".htmlpage($page));
- return;
- }
- }
+ # Internet Explod^Hrer won't show custom 404 responses
+ # unless they're >= 512 bytes
+ print ' ' x 512;
- my @editable_locs = grep {
- check_canedit($_, $q, $session, 1)
- } @page_locs;
- if (! @editable_locs) {
- # let it throw an error this time
- map { check_canedit($_, $q, $session) } @page_locs;
- }
-
- my @page_types;
- if (exists $hooks{htmlize}) {
- @page_types=grep { !/^_/ }
- keys %{$hooks{htmlize}};
- }
-
- $form->tmpl_param("page_select", 1);
- $form->field(name => "page", type => 'select',
- options => [ map { [ $_, pagetitle($_, 1) ] } @editable_locs ],
- value => $best_loc);
- $form->field(name => "type", type => 'select',
- options => \@page_types);
- $form->title(sprintf(gettext("creating %s"), pagetitle($page)));
-
- }
- elsif ($form->field("do") eq "edit") {
- check_canedit($page, $q, $session);
- if (! defined $form->field('editcontent') ||
- ! length $form->field('editcontent')) {
- my $content="";
- if (exists $pagesources{$page}) {
- $content=readfile(srcfile($pagesources{$page}));
- $content=~s/\n/\r\n/g;
- }
- $form->field(name => "editcontent", value => $content,
- force => 1);
- }
- $form->tmpl_param("page_select", 0);
- $form->field(name => "page", type => 'hidden');
- $form->field(name => "type", type => 'hidden');
- $form->title(sprintf(gettext("editing %s"), pagetitle($page)));
- }
-
- showform($form, \@buttons, $session, $q, forcebaseurl => $baseurl);
- }
- else {
- # save page
- check_canedit($page, $q, $session);
-
- # The session id is stored on the form and checked to
- # guard against CSRF. But only if the user is logged in,
- # as anonok can allow anonymous edits.
- if (defined $session->param("name")) {
- my $sid=$q->param('sid');
- if (! defined $sid || $sid ne $session->id) {
- error(gettext("Your login session has expired."));
- }
- }
+ exit;
+}
- my $exists=-e "$config{srcdir}/$file";
-
- if ($form->field("do") ne "create" && ! $exists &&
- ! defined srcfile($file, 1)) {
- $form->tmpl_param("page_gone", 1);
- $form->field(name => "do", value => "create", force => 1);
- $form->tmpl_param("page_select", 0);
- $form->field(name => "page", type => 'hidden');
- $form->field(name => "type", type => 'hidden');
- $form->title(sprintf(gettext("editing %s"), $page));
- showform($form, \@buttons, $session, $q, forcebaseurl => $baseurl);
- return;
- }
- elsif ($form->field("do") eq "create" && $exists) {
- $form->tmpl_param("creation_conflict", 1);
- $form->field(name => "do", value => "edit", force => 1);
- $form->tmpl_param("page_select", 0);
- $form->field(name => "page", type => 'hidden');
- $form->field(name => "type", type => 'hidden');
- $form->title(sprintf(gettext("editing %s"), $page));
- $form->field("editcontent",
- value => readfile("$config{srcdir}/$file").
- "\n\n\n".$form->field("editcontent"),
- force => 1);
- showform($form, \@buttons, $session, $q, forcebaseurl => $baseurl);
- return;
- }
-
- my $content=$form->field('editcontent');
- run_hooks(editcontent => sub {
- $content=shift->(
- content => $content,
- page => $page,
- cgi => $q,
- session => $session,
- );
- });
- $content=~s/\r\n/\n/g;
- $content=~s/\r/\n/g;
- $content.="\n" if $content !~ /\n$/;
-
- $config{cgi}=0; # avoid cgi error message
- eval { writefile($file, $config{srcdir}, $content) };
- $config{cgi}=1;
- if ($@) {
- $form->field(name => "rcsinfo", value => rcs_prepedit($file),
- force => 1);
- $form->tmpl_param("failed_save", 1);
- $form->tmpl_param("error_message", $@);
- $form->field("editcontent", value => $content, force => 1);
- $form->tmpl_param("page_select", 0);
- $form->field(name => "page", type => 'hidden');
- $form->field(name => "type", type => 'hidden');
- $form->title(sprintf(gettext("editing %s"), $page));
- showform($form, \@buttons, $session, $q,
- forcebaseurl => $baseurl);
- return;
- }
-
- my $conflict;
- if ($config{rcs}) {
- my $message="";
- if (defined $form->field('comments') &&
- length $form->field('comments')) {
- $message=$form->field('comments');
- }
-
- if (! $exists) {
- rcs_add($file);
- }
+sub check_banned ($$) {
+ my $q=shift;
+ my $session=shift;
- # Prevent deadlock with post-commit hook by
- # signaling to it that it should not try to
- # do anything.
- disable_commit_hook();
- $conflict=rcs_commit($file, $message,
- $form->field("rcsinfo"),
- $session->param("name"), $ENV{REMOTE_ADDR});
- enable_commit_hook();
- rcs_update();
- }
-
- # Refresh even if there was a conflict, since other changes
- # may have been committed while the post-commit hook was
- # disabled.
- require IkiWiki::Render;
- refresh();
- saveindex();
-
- if (defined $conflict) {
- $form->field(name => "rcsinfo", value => rcs_prepedit($file),
- force => 1);
- $form->tmpl_param("page_conflict", 1);
- $form->field("editcontent", value => $conflict, force => 1);
- $form->field("do", "edit", force => 1);
- $form->tmpl_param("page_select", 0);
- $form->field(name => "page", type => 'hidden');
- $form->field(name => "type", type => 'hidden');
- $form->title(sprintf(gettext("editing %s"), $page));
- showform($form, \@buttons, $session, $q,
- forcebaseurl => $baseurl);
- return;
- }
- else {
- # The trailing question mark tries to avoid broken
- # caches and get the most recent version of the page.
- redirect($q, "$config{url}/".htmlpage($page)."?updated");
+ my $name=$session->param("name");
+ if (defined $name) {
+ if (grep { $name eq $_ } @{$config{banned_users}}) {
+ $session->delete();
+ cgi_savesession($session);
+ cgi_custom_failure(
+ $q->header(-status => "403 Forbidden"),
+ gettext("You are banned."));
}
}
-} #}}}
+}
-sub cgi_getsession ($) { #{{{
+sub cgi_getsession ($) {
my $q=shift;
- eval q{use CGI::Session};
+ eval q{use CGI::Session; use HTML::Entities};
error($@) if $@;
- CGI::Session->name("ikiwiki_session_".encode_utf8($config{wikiname}));
+ CGI::Session->name("ikiwiki_session_".encode_entities($config{wikiname}));
my $oldmask=umask(077);
- my $session = CGI::Session->new("driver:DB_File", $q,
- { FileName => "$config{wikistatedir}/sessions.db" });
+ my $session = eval {
+ CGI::Session->new("driver:DB_File", $q,
+ { FileName => "$config{wikistatedir}/sessions.db" })
+ };
+ if (! $session || $@) {
+ error($@." ".CGI::Session->errstr());
+ }
+
umask($oldmask);
return $session;
-} #}}}
+}
+
+# To guard against CSRF, the user's session id (sid)
+# can be stored on a form. This function will check
+# (for logged in users) that the sid on the form matches
+# the session id in the cookie.
+sub checksessionexpiry ($$) {
+ my $q=shift;
+ my $session = shift;
-sub cgi_savesession ($) { #{{{
+ if (defined $session->param("name")) {
+ my $sid=$q->param('sid');
+ if (! defined $sid || $sid ne $session->id) {
+ error(gettext("Your login session has expired."));
+ }
+ }
+}
+
+sub cgi_savesession ($) {
my $session=shift;
# Force session flush with safe umask.
my $oldmask=umask(077);
$session->flush;
umask($oldmask);
-} #}}}
+}
-sub cgi (;$$) { #{{{
+sub cgi (;$$) {
my $q=shift;
my $session=shift;
error("\"do\" parameter missing");
}
}
-
+
# Need to lock the wiki before getting a session.
lockwiki();
loadindex();
}
}
- if (defined $session->param("name") &&
- userinfo_get($session->param("name"), "banned")) {
- print $q->header(-status => "403 Forbidden");
- $session->delete();
- print gettext("You are banned.");
- cgi_savesession($session);
- }
-
+ check_banned($q, $session);
+
run_hooks(sessioncgi => sub { shift->($q, $session) });
if ($do eq 'signin') {
elsif ($do eq 'prefs') {
cgi_prefs($q, $session);
}
- elsif ($do eq 'create' || $do eq 'edit') {
- cgi_editpage($q, $session);
- }
elsif (defined $session->param("postsignin") || $do eq 'postsignin') {
cgi_postsignin($q, $session);
}
else {
error("unknown do parameter");
}
-} #}}}
+}
+
+# Does not need to be called directly; all errors will go through here.
+sub cgierror ($) {
+ my $message=shift;
+
+ print "Content-type: text/html\n\n";
+ print misctemplate(gettext("Error"),
+ "<p class=\"error\">".gettext("Error").": $message</p>");
+ die $@;
+}
1
--- /dev/null
+#!/usr/bin/perl
+# Copyright © 2009 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+# Licensed under the GNU GPL, version 2, or any later version published by the
+# Free Software Foundation
+package IkiWiki::Plugin::404;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "cgi", id => '404', call => \&cgi);
+ IkiWiki::loadplugin("goto");
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ # not really a matter of safety, but enabling/disabling
+ # through a web interface is useless - it needs web
+ # server admin action too
+ safe => 0,
+ rebuild => 0,
+ }
+}
+
+sub cgi_page_from_404 ($$$) {
+ my $path = shift;
+ my $baseurl = shift;
+ my $usedirs = shift;
+
+ # fail if missing from environment or whatever
+ return undef unless defined $path;
+ return undef unless defined $baseurl;
+
+ # with usedirs on, path is like /~fred/foo/bar/ or /~fred/foo/bar or
+ # /~fred/foo/bar/index.html
+ # with usedirs off, path is like /~fred/foo/bar.html
+ # baseurl is like 'http://people.example.com/~fred'
+
+ # convert baseurl to ~fred
+ unless ($baseurl =~ s{^https?://[^/]+/?}{}) {
+ return undef;
+ }
+
+ # convert path to /~fred/foo/bar
+ if ($usedirs) {
+ $path =~ s/\/*(?:index\.$config{htmlext})?$//;
+ }
+ else {
+ $path =~ s/\.$config{htmlext}$//;
+ }
+
+ # remove /~fred/
+ unless ($path =~ s{^/*\Q$baseurl\E/*}{}) {
+ return undef;
+ }
+
+ # special case for the index
+ unless ($path) {
+ return 'index';
+ }
+
+ return $path;
+}
+
+sub cgi ($) {
+ my $cgi=shift;
+
+ if (exists $ENV{REDIRECT_STATUS} &&
+ $ENV{REDIRECT_STATUS} eq '404') {
+ my $page = cgi_page_from_404($ENV{REDIRECT_URL},
+ $config{url}, $config{usedirs});
+ IkiWiki::Plugin::goto::cgi_goto($cgi, $page);
+ }
+}
+
+1;
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use HTML::Parser;
use HTML::Tagset;
use HTML::Entities;
my %feeds;
my %guids;
-sub import { #{{{
+sub import {
hook(type => "getopt", id => "aggregate", call => \&getopt);
+ hook(type => "getsetup", id => "aggregate", call => \&getsetup);
hook(type => "checkconfig", id => "aggregate", call => \&checkconfig);
hook(type => "needsbuild", id => "aggregate", call => \&needsbuild);
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);
}
-} # }}}
+}
-sub getopt () { #{{{
+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 getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ aggregateinternal => {
+ type => "boolean",
+ example => 1,
+ description => "enable aggregation to internal pages?",
+ safe => 0, # enabling needs manual transition
+ rebuild => 0,
+ },
+ aggregate_webtrigger => {
+ type => "boolean",
+ example => 0,
+ description => "allow aggregation to be triggered via the web?",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
+ if (! defined $config{aggregateinternal}) {
+ $config{aggregateinternal}=1;
+ }
-sub checkconfig () { #{{{
if ($config{aggregate} && ! ($config{post_commit} &&
IkiWiki::commit_hook_enabled())) {
launchaggregation();
}
-} #}}}
+}
-sub cgi ($) { #{{{
+sub cgi ($) {
my $cgi=shift;
if (defined $cgi->param('do') &&
}
exit 0;
}
-} #}}}
+}
-sub launchaggregation () { #{{{
+sub launchaggregation () {
# See if any feeds need aggregation.
loadstate();
my @feeds=needsaggregate();
unlockaggregate();
return 1;
-} #}}}
+}
+
+# Pages with extension _aggregated have plain html markup, pass through.
+sub htmlize (@) {
+ my %params=@_;
+ return $params{content};
+}
-sub needsbuild (@) { #{{{
+# 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 = "$config{srcdir}/".htmlfn($data->{page});
+ my $oldoutput = $config{destdir}."/".IkiWiki::htmlpage($data->{page});
+
+ $config{aggregateinternal} = 1;
+ my $newname = "$config{srcdir}/".htmlfn($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;
loadstate();
markunseen($feed->{sourcepage});
}
}
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
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)
}
}
$feed->{name}=$name;
$feed->{sourcepage}=$params{page};
$feed->{url}=$params{url};
- my $dir=exists $params{dir} ? $params{dir} : $params{page}."/".IkiWiki::titlepage($params{name});
+ my $dir=exists $params{dir} ? $params{dir} : $params{page}."/".titlepage($params{name});
$dir=~s/^\/+//;
($dir)=$dir=~/$config{wiki_file_regexp}/;
$feed->{dir}=$dir;
$feed->{template}=$params{template} . ".tmpl";
delete $feed->{unseen};
$feed->{lastupdate}=0 unless defined $feed->{lastupdate};
+ $feed->{lasttry}=$feed->{lastupdate} unless defined $feed->{lasttry};
$feed->{numposts}=0 unless defined $feed->{numposts};
$feed->{newposts}=0 unless defined $feed->{newposts};
$feed->{message}=gettext("new feed") unless defined $feed->{message};
($feed->{newposts} ? "; ".$feed->{newposts}.
" ".gettext("new") : "").
")";
-} # }}}
+}
-sub delete (@) { #{{{
+sub delete (@) {
my @files=@_;
# Remove feed data for removed pages.
my $page=pagename($file);
markunseen($page);
}
-} #}}}
+}
-sub markunseen ($) { #{{{
+sub markunseen ($) {
my $page=shift;
foreach my $id (keys %feeds) {
$feeds{$id}->{unseen}=1;
}
}
-} #}}}
+}
my $state_loaded=0;
-sub loadstate () { #{{{
+sub loadstate () {
return if $state_loaded;
$state_loaded=1;
if (-e "$config{wikistatedir}/aggregate") {
close IN;
}
-} #}}}
+}
-sub savestate () { #{{{
+sub savestate () {
return unless $state_loaded;
garbage_collect();
my $newfile="$config{wikistatedir}/aggregate.new";
push @line, "tag=$_" foreach @{$data->{tags}};
}
else {
- push @line, "$field=".$data->{$field};
+ push @line, "$field=".$data->{$field}
+ if defined $data->{$field};
}
}
print OUT join(" ", @line)."\n" || error("write $newfile: $!", $cleanup);
close OUT || error("save $newfile: $!", $cleanup);
rename($newfile, "$config{wikistatedir}/aggregate") ||
error("rename $newfile: $!", $cleanup);
-} #}}}
+}
-sub garbage_collect () { #{{{
+sub garbage_collect () {
foreach my $name (keys %feeds) {
# remove any feeds that were not seen while building the pages
# that used to contain them
foreach my $guid (values %guids) {
# any guid whose feed is gone should be removed
if (! exists $feeds{$guid->{feed}}) {
- unlink pagefile($guid->{page})
+ unlink "$config{srcdir}/".htmlfn($guid->{page})
if exists $guid->{page};
delete $guids{$guid->{guid}};
}
# handle expired guids
elsif ($guid->{expired} && exists $guid->{page}) {
- unlink pagefile($guid->{page});
+ unlink "$config{srcdir}/".htmlfn($guid->{page});
delete $guid->{page};
delete $guid->{md5};
}
}
-} #}}}
+}
-sub mergestate () { #{{{
+sub mergestate () {
# Load the current state in from disk, and merge into it
# values from the state in memory that might have changed
# during aggregation.
# fields.
foreach my $name (keys %myfeeds) {
if (exists $feeds{$name}) {
- foreach my $field (qw{message lastupdate numposts
- newposts error}) {
+ foreach my $field (qw{message lastupdate lasttry
+ numposts newposts error}) {
$feeds{$name}->{$field}=$myfeeds{$name}->{$field};
}
}
}
# New guids can be created during aggregation.
+ # Guids have a few fields that may be updated during aggregation.
# It's also possible that guids were removed from the on-disk state
# while the aggregation was in process. That would only happen if
# their feed was also removed, so any removed guids added back here
if (! exists $guids{$guid}) {
$guids{$guid}=$myguids{$guid};
}
+ else {
+ foreach my $field (qw{md5}) {
+ $guids{$guid}->{$field}=$myguids{$guid}->{$field};
+ }
+ }
}
-} #}}}
+}
-sub clearstate () { #{{{
+sub clearstate () {
%feeds=();
%guids=();
$state_loaded=0;
-} #}}}
+}
-sub expire () { #{{{
+sub expire () {
foreach my $feed (values %feeds) {
next unless $feed->{expireage} || $feed->{expirecount};
my $count=0;
my %seen;
- foreach my $item (sort { $IkiWiki::pagectime{$b->{page}} <=> $IkiWiki::pagectime{$a->{page}} }
- grep { exists $_->{page} && $_->{feed} eq $feed->{name} && $IkiWiki::pagectime{$_->{page}} }
+ foreach my $item (sort { ($IkiWiki::pagectime{$b->{page}} || 0) <=> ($IkiWiki::pagectime{$a->{page}} || 0) }
+ grep { exists $_->{page} && $_->{feed} eq $feed->{name} }
values %guids) {
if ($feed->{expireage}) {
- my $days_old = (time - $IkiWiki::pagectime{$item->{page}}) / 60 / 60 / 24;
+ my $days_old = (time - ($IkiWiki::pagectime{$item->{page}} || 0)) / 60 / 60 / 24;
if ($days_old > $feed->{expireage}) {
debug(sprintf(gettext("expiring %s (%s days old)"),
$item->{page}, int($days_old)));
}
}
}
-} #}}}
+}
-sub needsaggregate () { #{{{
+sub needsaggregate () {
return values %feeds if $config{rebuild};
return grep { time - $_->{lastupdate} >= $_->{updateinterval} } values %feeds;
-} #}}}
+}
-sub aggregate (@) { #{{{
+sub aggregate (@) {
eval q{use XML::Feed};
error($@) if $@;
eval q{use URI::Fetch};
error($@) if $@;
foreach my $feed (@_) {
- $feed->{lastupdate}=time;
+ $feed->{lasttry}=time;
$feed->{newposts}=0;
- $feed->{message}=sprintf(gettext("processed ok at %s"),
- displaytime($feed->{lastupdate}));
+ $feed->{message}=sprintf(gettext("last checked %s"),
+ displaytime($feed->{lasttry}));
$feed->{error}=0;
debug(sprintf(gettext("checking feed %s ..."), $feed->{name}));
debug($feed->{message});
next;
}
+
+ # lastupdate is only set if we were able to contact the server
+ $feed->{lastupdate}=$feed->{lasttry};
+
if ($res->status == URI::Fetch::URI_GONE()) {
$feed->{message}=gettext("feed not found");
$feed->{error}=1;
# that contains invalid UTF-8 sequences. Convert
# feed to ascii to try to work around.
$feed->{message}.=" ".sprintf(gettext("(invalid UTF-8 stripped from feed)"));
- $content=Encode::decode_utf8($content, 0);
- $f=eval{XML::Feed->parse(\$content)};
+ $f=eval {
+ $content=Encode::decode_utf8($content, 0);
+ XML::Feed->parse(\$content)
+ };
}
if ($@) {
# Another possibility is badly escaped entities.
$feed->{message}.=" ".sprintf(gettext("(feed entities escaped)"));
$content=~s/\&(?!amp)(\w+);/&$1;/g;
- $content=Encode::decode_utf8($content, 0);
- $f=eval{XML::Feed->parse(\$content)};
+ $f=eval {
+ $content=Encode::decode_utf8($content, 0);
+ XML::Feed->parse(\$content)
+ };
}
if ($@) {
$feed->{message}=gettext("feed crashed XML::Feed!")." ($@)";
}
foreach my $entry ($f->entries) {
+ # XML::Feed doesn't work around XML::Atom's bizarre
+ # API, so we will. Real unicode strings? Yes please.
+ # See [[bugs/Aggregated_Atom_feeds_are_double-encoded]]
+ local $XML::Atom::ForceUnicode = 1;
+
+ my $c=$entry->content;
+ # atom feeds may have no content, only a summary
+ if (! defined $c && ref $entry->summary) {
+ $c=$entry->summary;
+ }
+
add_page(
feed => $feed,
copyright => $f->copyright,
title => defined $entry->title ? decode_entities($entry->title) : "untitled",
link => $entry->link,
- content => defined $entry->content->body ? $entry->content->body : "",
+ content => (defined $c && defined $c->body) ? $c->body : "",
guid => defined $entry->id ? $entry->id : time."_".$feed->{name},
ctime => $entry->issued ? ($entry->issued->epoch || time) : time,
+ base => (defined $c && $c->can("base")) ? $c->base : undef,
);
}
}
-} #}}}
+}
-sub add_page (@) { #{{{
+sub add_page (@) {
my %params=@_;
my $feed=$params{feed};
$feed->{newposts}++;
# assign it an unused page
- my $page=IkiWiki::titlepage($params{title});
+ my $page=titlepage($params{title});
# escape slashes and periods in title so it doesn't specify
# directory name or trigger ".." disallowing code.
$page=~s!([/.])!"__".ord($1)."__"!eg;
}
my $c="";
while (exists $IkiWiki::pagecase{lc $page.$c} ||
- -e pagefile($page.$c)) {
+ -e "$config{srcdir}/".htmlfn($page.$c)) {
$c++
}
$c="";
$page=$feed->{dir}."/item";
while (exists $IkiWiki::pagecase{lc $page.$c} ||
- -e pagefile($page.$c)) {
+ -e "$config{srcdir}/".htmlfn($page.$c)) {
$c++
}
}
my $template=template($feed->{template}, blind_cache => 1);
$template->param(title => $params{title})
if defined $params{title} && length($params{title});
- $template->param(content => htmlescape(htmlabs($params{content}, $feed->{feedurl})));
+ $template->param(content => wikiescape(htmlabs($params{content},
+ defined $params{base} ? $params{base} : $feed->{feedurl})));
$template->param(name => $feed->{name});
$template->param(url => $feed->{url});
$template->param(copyright => $params{copyright})
writefile(htmlfn($guid->{page}), $config{srcdir},
$template->output);
- # Set the mtime, this lets the build process get the right creation
- # time on record for the new page.
- utime $mtime, $mtime, pagefile($guid->{page})
- if defined $mtime && $mtime <= time;
-} #}}}
+ if (defined $mtime && $mtime <= time) {
+ # Set the mtime, this lets the build process get the right
+ # creation time on record for the new page.
+ utime $mtime, $mtime, "$config{srcdir}/".htmlfn($guid->{page});
+ # Store it in pagectime for expiry code to use also.
+ $IkiWiki::pagectime{$guid->{page}}=$mtime
+ unless exists $IkiWiki::pagectime{$guid->{page}};
+ }
+ else {
+ # Dummy value for expiry code.
+ $IkiWiki::pagectime{$guid->{page}}=time
+ unless exists $IkiWiki::pagectime{$guid->{page}};
+ }
+}
-sub htmlescape ($) { #{{{
+sub wikiescape ($) {
# escape accidental wikilinks and preprocessor stuff
- my $html=shift;
- $html=~s/(?<!\\)\[\[/\\\[\[/g;
- return $html;
-} #}}}
+ return encode_entities(shift, '\[\]');
+}
-sub urlabs ($$) { #{{{
+sub urlabs ($$) {
my $url=shift;
my $urlbase=shift;
URI->new_abs($url, $urlbase)->as_string;
-} #}}}
+}
-sub htmlabs ($$) { #{{{
+sub htmlabs ($$) {
# Convert links in html from relative to absolute.
# Note that this is a heuristic, which is not specified by the rss
# spec and may not be right for all feeds. Also, see Debian
$p->eof;
return $ret;
-} #}}}
-
-sub pagefile ($) { #{{{
- my $page=shift;
-
- return "$config{srcdir}/".htmlfn($page);
-} #}}}
+}
-sub htmlfn ($) { #{{{
- return shift().".".$config{htmlext};
-} #}}}
+sub htmlfn ($) {
+ return shift().".".($config{aggregateinternal} ? "_aggregated" : $config{htmlext});
+}
my $aggregatelock;
-sub lockaggregate () { #{{{
+sub lockaggregate () {
# Take an exclusive lock to prevent multiple concurrent aggregators.
# Returns true if the lock was aquired.
if (! -d $config{wikistatedir}) {
return 0;
}
return 1;
-} #}}}
+}
-sub unlockaggregate () { #{{{
+sub unlockaggregate () {
return close($aggregatelock) if $aggregatelock;
return;
-} #}}}
+}
1
use warnings;
no warnings 'redefine';
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use IkiWiki::Render;
use Net::Amazon::S3;
}
};
-sub import { #{{{
+sub import {
hook(type => "getopt", id => "amazon_s3", call => \&getopt);
+ hook(type => "getsetup", id => "amazon_s3", call => \&getsetup);
hook(type => "checkconfig", id => "amazon_s3", call => \&checkconfig);
-} # }}}
+}
-sub getopt () { #{{{
+sub getopt () {
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
debug(gettext("done"));
exit(0);
});
-} #}}}
+}
-sub checkconfig { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0,
+ rebuild => 0,
+ },
+ amazon_s3_key_id => {
+ type => "string",
+ example => "XXXXXXXXXXXXXXXXXXXX",
+ description => "public access key id",
+ safe => 1,
+ rebuild => 0,
+ },
+ amazon_s3_key_id => {
+ type => "string",
+ example => "$ENV{HOME}/.s3_key",
+ description => "file holding secret key (must not be readable by others!)",
+ safe => 0, # ikiwiki reads this file
+ rebuild => 0,
+ },
+ amazon_s3_bucket => {
+ type => "string",
+ example => "mywiki",
+ description => "globally unique name of bucket to store wiki in",
+ safe => 1,
+ rebuild => 1,
+ },
+ amazon_s3_prefix => {
+ type => "string",
+ example => "wiki/",
+ description => "a prefix to prepend to each page name",
+ safe => 1,
+ rebuild => 1,
+ },
+ amazon_s3_location => {
+ type => "string",
+ example => "EU",
+ description => "which S3 datacenter to use (leave blank for default)",
+ safe => 1,
+ rebuild => 1,
+ },
+ amazon_s3_dupindex => {
+ type => "boolean",
+ example => 0,
+ description => "store each index file twice? (allows urls ending in \"/index.html\" and \"/\")",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig {
foreach my $field (qw{amazon_s3_key_id amazon_s3_key_file
amazon_s3_bucket}) {
if (! exists $config{$field} || ! defined $config{$field}) {
! defined $config{amazon_s3_prefix}) {
$config{amazon_s3_prefix}="wiki/";
}
-} #}}}
+}
{
my $bucket;
-sub getbucket { #{{{
+sub getbucket {
return $bucket if defined $bucket;
open(IN, "<", $config{amazon_s3_key_file}) || error($config{amazon_s3_key_file}.": ".$!);
}
if (! $bucket) {
- error(gettext("Failed to create bucket in S3: ").
+ error(gettext("Failed to create S3 bucket: ").
$s3->err.": ".$s3->errstr."\n");
}
return $bucket;
-} #}}}
+}
}
# Given a file, return any S3 keys associated with it.
-sub file2keys ($) { #{{{
+sub file2keys ($) {
my $file=shift;
my @keys;
}
}
return @keys;
-} #}}}
+}
package IkiWiki;
use File::MimeInfo;
use Encode;
# This is a wrapper around the real writefile.
-sub writefile ($$$;$$) { #{{{
+sub writefile ($$$;$$) {
my $file=shift;
my $destdir=shift;
my $content=shift;
}
return $ret;
-} #}}}
+}
# This is a wrapper around the real prune.
-sub prune ($) { #{{{
+sub prune ($) {
my $file=shift;
my @keys=IkiWiki::Plugin::amazon_s3::file2keys($file);
}
return $IkiWiki::Plugin::amazon_s3::subs{'IkiWiki::prune'}->($file);
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
- hook(type => "canedit", id => "anonok", call => \&canedit,);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "anonok", call => \&getsetup);
+ hook(type => "canedit", id => "anonok", call => \&canedit);
+}
-sub canedit ($$$) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ anonok_pagespec => {
+ type => "pagespec",
+ example => "*/discussion",
+ description => "PageSpec to limit which pages anonymous users can edit",
+ link => "ikiwiki/PageSpec",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub canedit ($$$) {
my $page=shift;
my $cgi=shift;
my $session=shift;
else {
return "";
}
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ add_underlay("javascript");
+ hook(type => "getsetup", id => "attachment", call => \&getsetup);
hook(type => "checkconfig", id => "attachment", call => \&checkconfig);
hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup);
hook(type => "formbuilder", id => "attachment", call => \&formbuilder);
-} # }}}
+ IkiWiki::loadplugin("filecheck");
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ allowed_attachments => {
+ type => "pagespec",
+ example => "virusfree() and mimetype(image/*) and maxsize(50kb)",
+ description => "enhanced PageSpec specifying what attachments are allowed",
+ link => "ikiwiki/PageSpec/attachment",
+ safe => 1,
+ rebuild => 0,
+ },
+ virus_checker => {
+ type => "string",
+ example => "clamdscan -",
+ description => "virus checker program (reads STDIN, returns nonzero if virus found)",
+ safe => 0, # executed
+ rebuild => 0,
+ },
+}
-sub checkconfig () { #{{{
+sub check_canattach ($$;$) {
+ my $session=shift;
+ my $dest=shift; # where it's going to be put, under the srcdir
+ my $file=shift; # the path to the attachment currently
+
+ # Don't allow an attachment to be uploaded with the same name as an
+ # existing page.
+ if (exists $IkiWiki::pagesources{$dest} &&
+ $IkiWiki::pagesources{$dest} ne $dest) {
+ error(sprintf(gettext("there is already a page named %s"), $dest));
+ }
+
+ # Use a special pagespec to test that the attachment is valid.
+ my $allowed=1;
+ if (defined $config{allowed_attachments} &&
+ length $config{allowed_attachments}) {
+ $allowed=pagespec_match($dest,
+ $config{allowed_attachments},
+ file => $file,
+ user => $session->param("name"),
+ ip => $ENV{REMOTE_ADDR},
+ );
+ }
+
+ if (! $allowed) {
+ error(gettext("prohibited by allowed_attachments")." ($allowed)");
+ }
+ else {
+ return 1;
+ }
+}
+
+sub checkconfig () {
$config{cgi_disable_uploads}=0;
-} #}}}
+}
-sub formbuilder_setup (@) { #{{{
+sub formbuilder_setup (@) {
my %params=@_;
my $form=$params{form};
my $q=$params{cgi};
- if (defined $form->field("do") && $form->field("do") eq "edit") {
+ if (defined $form->field("do") && ($form->field("do") eq "edit" ||
+ $form->field("do") eq "create")) {
+ # Add attachment field, set type to multipart.
+ $form->enctype(&CGI::MULTIPART);
$form->field(name => 'attachment', type => 'file');
# These buttons are not put in the usual place, so
# are not added to the normal formbuilder button list.
$form->tmpl_param("field-upload" => '<input name="_submit" type="submit" value="Upload Attachment" />');
$form->tmpl_param("field-link" => '<input name="_submit" type="submit" value="Insert Links" />');
- # Add the javascript from the toggle plugin;
- # the attachments interface uses it to toggle visibility.
+ # Add the toggle javascript; the attachments interface uses
+ # it to toggle visibility.
require IkiWiki::Plugin::toggle;
- $form->tmpl_param("javascript" => $IkiWiki::Plugin::toggle::javascript);
+ $form->tmpl_param("javascript" => IkiWiki::Plugin::toggle::include_javascript($params{page}, 1));
# Start with the attachments interface toggled invisible,
# but if it was used, keep it open.
if ($form->submitted ne "Upload Attachment" &&
- ! length $q->param("attachment_select")) {
+ (! defined $q->param("attachment_select") ||
+ ! length $q->param("attachment_select"))) {
$form->tmpl_param("attachments-class" => "toggleable");
}
else {
$form->tmpl_param("attachments-class" => "toggleable-open");
}
}
- elsif ($form->title eq "preferences") {
- my $session=$params{session};
- my $user_name=$session->param("name");
-
- $form->field(name => "allowed_attachments", size => 50,
- fieldset => "admin",
- comment => "(".
- htmllink("", "",
- "ikiwiki/PageSpec/attachment",
- noimageinline => 1,
- linktext => "Enhanced PageSpec",
- ).")"
- );
- if (! IkiWiki::is_admin($user_name)) {
- $form->field(name => "allowed_attachments", type => "hidden");
- }
- if (! $form->submitted) {
- $form->field(name => "allowed_attachments", force => 1,
- value => IkiWiki::userinfo_get($user_name, "allowed_attachments"));
- }
- if ($form->submitted && $form->submitted eq 'Save Preferences') {
- if (defined $form->field("allowed_attachments")) {
- IkiWiki::userinfo_set($user_name, "allowed_attachments",
- $form->field("allowed_attachments")) ||
- error("failed to set allowed_attachments");
- }
- }
- }
-} #}}}
+}
-sub formbuilder (@) { #{{{
+sub formbuilder (@) {
my %params=@_;
my $form=$params{form};
my $q=$params{cgi};
- return if ! defined $form->field("do") || $form->field("do") ne "edit";
+ return if ! defined $form->field("do") || ($form->field("do") ne "edit" && $form->field("do") ne "create") ;
my $filename=$q->param('attachment');
if (defined $filename && length $filename &&
# This is an (apparently undocumented) way to get the name
# of the temp file that CGI writes the upload to.
my $tempfile=$q->tmpFileName($filename);
-
- $filename=IkiWiki::titlepage(
- IkiWiki::possibly_foolish_untaint(
+ if (! defined $tempfile || ! length $tempfile) {
+ # perl 5.8 needs an alternative, awful method
+ if ($q =~ /HASH/ && exists $q->{'.tmpfiles'}) {
+ foreach my $key (keys(%{$q->{'.tmpfiles'}})) {
+ $tempfile=$q->tmpFileName(\$key);
+ last if defined $tempfile && length $tempfile;
+ }
+ }
+ if (! defined $tempfile || ! length $tempfile) {
+ error("CGI::tmpFileName failed to return the uploaded file name");
+ }
+ }
+
+ $filename=linkpage(IkiWiki::possibly_foolish_untaint(
attachment_location($form->field('page')).
IkiWiki::basename($filename)));
if (IkiWiki::file_pruned($filename, $config{srcdir})) {
# Check that the user is allowed to edit a page with the
# name of the attachment.
IkiWiki::check_canedit($filename, $q, $session, 1);
-
- # Use a special pagespec to test that the attachment is valid.
- my $allowed=1;
- foreach my $admin (@{$config{adminuser}}) {
- my $allowed_attachments=IkiWiki::userinfo_get($admin, "allowed_attachments");
- if (defined $allowed_attachments &&
- length $allowed_attachments) {
- $allowed=pagespec_match($filename,
- $allowed_attachments,
- file => $tempfile,
- user => $session->param("name"),
- ip => $ENV{REMOTE_ADDR},
- );
- last if $allowed;
- }
- }
- if (! $allowed) {
- error(gettext("attachment rejected")." ($allowed)");
- }
+ # And that the attachment itself is acceptable.
+ check_canattach($session, $filename, $tempfile);
# Needed for fast_file_copy and for rendering below.
require IkiWiki::Render;
else {
my $fh=$q->upload('attachment');
if (! defined $fh || ! ref $fh) {
- error("failed to get filehandle");
+ # needed by old CGI versions
+ $fh=$q->param('attachment');
+ if (! defined $fh || ! ref $fh) {
+ # even that doesn't always work,
+ # fall back to opening the tempfile
+ $fh=undef;
+ open($fh, "<", $tempfile) || error("failed to open \"$tempfile\": $!");
+ }
}
binmode($fh);
writefile($filename, $config{srcdir}, undef, 1, sub {
IkiWiki::saveindex();
}
elsif ($form->submitted eq "Insert Links") {
+ my $page=quotemeta($q->param("page"));
my $add="";
foreach my $f ($q->param("attachment_select")) {
+ $f=~s/^$page\///;
$add.="[[$f]]\n";
}
$form->field(name => 'editcontent',
# Generate the attachment list only after having added any new
# attachments.
$form->tmpl_param("attachment_list" => [attachment_list($form->field('page'))]);
-} # }}}
+}
sub attachment_location ($) {
my $page=shift;
my @ret;
foreach my $f (values %pagesources) {
- if (! defined IkiWiki::pagetype($f) &&
+ if (! defined pagetype($f) &&
$f=~m/^\Q$loc\E[^\/]+$/ &&
-e "$config{srcdir}/$f") {
push @ret, {
"field-select" => '<input type="checkbox" name="attachment_select" value="'.$f.'" />',
link => htmllink($page, $page, $f, noimageinline => 1),
- size => humansize((stat(_))[7]),
+ size => IkiWiki::Plugin::filecheck::humansize((stat(_))[7]),
mtime => displaytime($IkiWiki::pagemtime{$f}),
- mtime_raw => $IkiWiki::pagemtime{$f},
};
}
}
return sort { $b->{mtime_raw} <=> $a->{mtime_raw} || $a->{link} cmp $b->{link} } @ret;
}
-my %units=( # size in bytes
- B => 1,
- byte => 1,
- KB => 2 ** 10,
- kilobyte => 2 ** 10,
- K => 2 ** 10,
- KB => 2 ** 10,
- kilobyte => 2 ** 10,
- M => 2 ** 20,
- MB => 2 ** 20,
- megabyte => 2 ** 20,
- G => 2 ** 30,
- GB => 2 ** 30,
- gigabyte => 2 ** 30,
- T => 2 ** 40,
- TB => 2 ** 40,
- terabyte => 2 ** 40,
- P => 2 ** 50,
- PB => 2 ** 50,
- petabyte => 2 ** 50,
- E => 2 ** 60,
- EB => 2 ** 60,
- exabyte => 2 ** 60,
- Z => 2 ** 70,
- ZB => 2 ** 70,
- zettabyte => 2 ** 70,
- Y => 2 ** 80,
- YB => 2 ** 80,
- yottabyte => 2 ** 80,
- # ikiwiki, if you find you need larger data quantities, either modify
- # yourself to add them, or travel back in time to 2008 and kill me.
- # -- Joey
-);
-
-sub parsesize ($) { #{{{
- my $size=shift;
-
- no warnings;
- my $base=$size+0; # force to number
- use warnings;
- foreach my $unit (sort keys %units) {
- if ($size=~/[0-9\s]\Q$unit\E$/i) {
- return $base * $units{$unit};
- }
- }
- return $base;
-} #}}}
-
-sub humansize ($) { #{{{
- my $size=shift;
-
- foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
- if ($size / $units{$unit} > 0.25) {
- return (int($size / $units{$unit} * 10)/10).$unit;
- }
- }
- return $size; # near zero, or negative
-} #}}}
-
-package IkiWiki::PageSpec;
-
-sub match_maxsize ($$;@) { #{{{
- shift;
- my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
- if ($@) {
- return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
- }
-
- my %params=@_;
- if (! exists $params{file}) {
- return IkiWiki::FailReason->new("no file specified");
- }
-
- if (-s $params{file} > $maxsize) {
- return IkiWiki::FailReason->new("file too large (".(-s $params{file})." > $maxsize)");
- }
- else {
- return IkiWiki::SuccessReason->new("file not too large");
- }
-} #}}}
-
-sub match_minsize ($$;@) { #{{{
- shift;
- my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
- if ($@) {
- return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
- }
-
- my %params=@_;
- if (! exists $params{file}) {
- return IkiWiki::FailReason->new("no file specified");
- }
-
- if (-s $params{file} < $minsize) {
- return IkiWiki::FailReason->new("file too small");
- }
- else {
- return IkiWiki::SuccessReason->new("file not too small");
- }
-} #}}}
-
-sub match_mimetype ($$;@) { #{{{
- shift;
- my $wanted=shift;
-
- my %params=@_;
- if (! exists $params{file}) {
- return IkiWiki::FailReason->new("no file specified");
- }
-
- # Use ::magic to get the mime type, the idea is to only trust
- # data obtained by examining the actual file contents.
- eval q{use File::MimeInfo::Magic};
- if ($@) {
- return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
- }
- my $mimetype=File::MimeInfo::Magic::magic($params{file});
- if (! defined $mimetype) {
- $mimetype="unknown";
- }
-
- my $regexp=IkiWiki::glob2re($wanted);
- if ($mimetype!~/^$regexp$/i) {
- return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
- }
- else {
- return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
- }
-} #}}}
-
-sub match_virusfree ($$;@) { #{{{
- shift;
- my $wanted=shift;
-
- my %params=@_;
- if (! exists $params{file}) {
- return IkiWiki::FailReason->new("no file specified");
- }
-
- if (! exists $IkiWiki::config{virus_checker} ||
- ! length $IkiWiki::config{virus_checker}) {
- return IkiWiki::FailReason->new("no virus_checker configured");
- }
-
- # The file needs to be fed into the virus checker on stdin,
- # because the file is not world-readable, and if clamdscan is
- # used, clamd would fail to read it.
- eval q{use IPC::Open2};
- error($@) if $@;
- open (IN, "<", $params{file}) || return IkiWiki::FailReason->new("failed to read file");
- binmode(IN);
- my $sigpipe=0;
- $SIG{PIPE} = sub { $sigpipe=1 };
- my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker});
- my $reason=<CHECKER_OUT>;
- chomp $reason;
- 1 while (<CHECKER_OUT>);
- close(CHECKER_OUT);
- waitpid $pid, 0;
- $SIG{PIPE}="DEFAULT";
- if ($sigpipe || $?) {
- return IkiWiki::FailReason->new("file seems to contain a virus ($reason)");
- }
- else {
- return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
- }
-} #}}}
-
-sub match_ispage ($$;@) { #{{{
- my $filename=shift;
-
- if (defined IkiWiki::pagetype($filename)) {
- return IkiWiki::SuccessReason->new("file is a wiki page");
- }
- else {
- return IkiWiki::FailReason->new("file is not a wiki page");
- }
-} #}}}
-
-sub match_user ($$;@) { #{{{
- shift;
- my $user=shift;
- my %params=@_;
-
- if (! exists $params{user}) {
- return IkiWiki::FailReason->new("no user specified");
- }
-
- if (defined $params{user} && lc $params{user} eq lc $user) {
- return IkiWiki::SuccessReason->new("user is $user");
- }
- else {
- return IkiWiki::FailReason->new("user is $params{user}, not $user");
- }
-} #}}}
-
-sub match_ip ($$;@) { #{{{
- shift;
- my $ip=shift;
- my %params=@_;
-
- if (! exists $params{ip}) {
- return IkiWiki::FailReason->new("no IP specified");
- }
-
- if (defined $params{ip} && lc $params{ip} eq lc $ip) {
- return IkiWiki::SuccessReason->new("IP is $ip");
- }
- else {
- return IkiWiki::FailReason->new("IP is $params{ip}, not $ip");
- }
-} #}}}
-
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::autoindex;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use Encode;
+
+sub import {
+ hook(type => "getsetup", id => "autoindex", call => \&getsetup);
+ hook(type => "refresh", id => "autoindex", call => \&refresh);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub genindex ($) {
+ my $page=shift;
+ my $file=newpagefile($page, $config{default_pageext});
+ my $template=template("autoindex.tmpl");
+ $template->param(page => $page);
+ writefile($file, $config{srcdir}, $template->output);
+ if ($config{rcs}) {
+ IkiWiki::rcs_add($file);
+ }
+}
+
+sub refresh () {
+ eval q{use File::Find};
+ error($@) if $@;
+
+ my (%pages, %dirs);
+ foreach my $dir ($config{srcdir}, @{$config{underlaydirs}}, $config{underlaydir}) {
+ find({
+ no_chdir => 1,
+ wanted => sub {
+ $_=decode_utf8($_);
+ if (IkiWiki::file_pruned($_, $dir)) {
+ $File::Find::prune=1;
+ }
+ elsif (! -l $_) {
+ my ($f)=/$config{wiki_file_regexp}/; # untaint
+ return unless defined $f;
+ $f=~s/^\Q$dir\E\/?//;
+ return unless length $f;
+ return if $f =~ /\._([^.]+)$/; # skip internal page
+ if (! -d _) {
+ $pages{pagename($f)}=1;
+ }
+ elsif ($dir eq $config{srcdir}) {
+ $dirs{$f}=1;
+ }
+ }
+ }
+ }, $dir);
+ }
+
+ my %deleted;
+ if (ref $pagestate{index}{autoindex}{deleted}) {
+ %deleted=%{$pagestate{index}{autoindex}{deleted}};
+ foreach my $dir (keys %deleted) {
+ # remove deleted page state if the deleted page is re-added,
+ # or if all its subpages are deleted
+ if ($deleted{$dir} && (exists $pages{$dir} ||
+ ! grep /^$dir\/.*/, keys %pages)) {
+ delete $deleted{$dir};
+ }
+ }
+ $pagestate{index}{autoindex}{deleted}=\%deleted;
+ }
+
+ my @needed;
+ foreach my $dir (keys %dirs) {
+ if (! exists $pages{$dir} && ! $deleted{$dir} &&
+ grep /^$dir\/.*/, keys %pages) {
+ if (exists $IkiWiki::pagemtime{$dir}) {
+ # This page must have just been deleted, so
+ # don't re-add it. And remember it was
+ # deleted.
+ if (! ref $pagestate{index}{autoindex}{deleted}) {
+ $pagestate{index}{autoindex}{deleted}={};
+ }
+ ${$pagestate{index}{autoindex}{deleted}}{$dir}=1;
+ }
+ else {
+ push @needed, $dir;
+ }
+ }
+ }
+
+ if (@needed) {
+ if ($config{rcs}) {
+ IkiWiki::disable_commit_hook();
+ }
+ foreach my $page (@needed) {
+ genindex($page);
+ }
+ if ($config{rcs}) {
+ IkiWiki::rcs_commit_staged(
+ gettext("automatic index generation"),
+ undef, undef);
+ IkiWiki::enable_commit_hook();
+ }
+ }
+}
+
+1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::blogspam;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+my $defaulturl='http://test.blogspam.net:8888/';
+
+sub import {
+ hook(type => "getsetup", id => "blogspam", call => \&getsetup);
+ hook(type => "checkconfig", id => "blogspam", call => \&checkconfig);
+ hook(type => "checkcontent", id => "blogspam", call => \&checkcontent);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ blogspam_pagespec => {
+ type => 'pagespec',
+ example => 'postcomment(*)',
+ description => 'PageSpec of pages to check for spam',
+ link => 'ikiwiki/PageSpec',
+ safe => 1,
+ rebuild => 0,
+ },
+ blogspam_options => {
+ type => "string",
+ example => "blacklist=1.2.3.4,blacklist=8.7.6.5,max-links=10",
+ description => "options to send to blogspam server",
+ link => "http://blogspam.net/api/testComment.html#options",
+ safe => 1,
+ rebuild => 0,
+ },
+ blogspam_server => {
+ type => "string",
+ default => $defaulturl,
+ description => "blogspam server XML-RPC url",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
+ # This is done at checkconfig time because printing an error
+ # if the module is missing when a spam is posted would not
+ # let the admin know about the problem.
+ eval q{
+ use RPC::XML;
+ use RPC::XML::Client;
+ };
+ error $@ if $@;
+}
+
+sub checkcontent (@) {
+ my %params=@_;
+
+ if (exists $config{blogspam_pagespec}) {
+ return undef
+ if ! pagespec_match($params{page}, $config{blogspam_pagespec},
+ location => $params{page});
+ }
+
+ my $url=$defaulturl;
+ $url = $config{blogspam_server} if exists $config{blogspam_server};
+ my $client = RPC::XML::Client->new($url);
+
+ my @options = split(",", $config{blogspam_options})
+ if exists $config{blogspam_options};
+
+ # Allow short comments and whitespace-only edits, unless the user
+ # has overridden min-words themselves.
+ push @options, "min-words=0"
+ unless grep /^min-words=/i, @options;
+ # Wiki pages can have a lot of urls, unless the user specifically
+ # wants to limit them.
+ push @options, "exclude=lotsaurls"
+ unless grep /^max-links/i, @options;
+ # Unless the user specified a size check, disable such checking.
+ push @options, "exclude=size"
+ unless grep /^(?:max|min)-size/i, @options;
+ # This test has absurd false positives on words like "alpha"
+ # and "buy".
+ push @options, "exclude=stopwords";
+
+ my %req=(
+ ip => $ENV{REMOTE_ADDR},
+ comment => defined $params{diff} ? $params{diff} : $params{content},
+ subject => defined $params{subject} ? $params{subject} : "",
+ name => defined $params{author} ? $params{author} : "",
+ link => exists $params{url} ? $params{url} : "",
+ options => join(",", @options),
+ site => $config{url},
+ version => "ikiwiki ".$IkiWiki::version,
+ );
+ my $res = $client->send_request('testComment', \%req);
+
+ if (! ref $res || ! defined $res->value) {
+ debug("failed to get response from blogspam server ($url)");
+ return undef;
+ }
+ elsif ($res->value =~ /^SPAM:(.*)/) {
+ eval q{use Data::Dumper};
+ debug("blogspam server reports ".$res->value.": ".Dumper(\%req));
+ return gettext("Sorry, but that looks like spam to <a href=\"http://blogspam.net/\">blogspam</a>: ").$1;
+ }
+ elsif ($res->value ne 'OK') {
+ debug("blogspam server failure: ".$res->value);
+ return undef;
+ }
+ else {
+ return undef;
+ }
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "brokenlinks", call => \&getsetup);
hook(type => "preprocess", id => "brokenlinks", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
$params{pages}="*" unless defined $params{pages};
# register a dependency.
add_depends($params{page}, $params{pages});
- my %broken;
- foreach my $page (keys %links) {
- if (pagespec_match($page, $params{pages}, location => $params{page})) {
- my $discussion=gettext("discussion");
- my %seen;
- foreach my $link (@{$links{$page}}) {
- next if $seen{$link};
- $seen{$link}=1;
- next if $link =~ /.*\/\Q$discussion\E/i && $config{discussion};
- my $bestlink=bestlink($page, $link);
- next if length $bestlink;
- push @{$broken{$link}}, $page;
- }
+ my @broken;
+ foreach my $link (keys %IkiWiki::brokenlinks) {
+ next if $link =~ /.*\/\Q$config{discussionpage}\E/i && $config{discussion};
+
+ my @pages;
+ foreach my $page (@{$IkiWiki::brokenlinks{$link}}) {
+ push @pages, $page
+ if pagespec_match($page, $params{pages}, location => $params{page});
}
- }
+ next unless @pages;
- my @broken;
- foreach my $link (keys %broken) {
- my $page=$broken{$link}->[0];
+ my $page=$IkiWiki::brokenlinks{$link}->[0];
push @broken, sprintf(gettext("%s from %s"),
htmllink($page, $params{destpage}, $link, noimageinline => 1),
join(", ", map {
htmllink($params{page}, $params{destpage}, $_, noimageinline => 1)
- } @{$broken{$link}}));
+ } @pages)
+ );
}
- return gettext("There are no broken links!") unless %broken;
+ return gettext("There are no broken links!") unless @broken;
return "<ul>\n"
.join("\n",
map {
}
sort @broken)
."</ul>\n";
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::bzr;
+
+use warnings;
+use strict;
+use IkiWiki;
+use Encode;
+use open qw{:utf8 :std};
+
+sub import {
+ hook(type => "checkconfig", id => "bzr", call => \&checkconfig);
+ hook(type => "getsetup", id => "bzr", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub checkconfig () {
+ if (defined $config{bzr_wrapper} && length $config{bzr_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{bzr_wrapper},
+ wrappermode => (defined $config{bzr_wrappermode} ? $config{bzr_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ bzr_wrapper => {
+ type => "string",
+ #example => "", # FIXME add example
+ description => "bzr post-commit hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ bzr_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for bzr_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ #example => "", # FIXME add example
+ description => "url to show file history, using loggerhead ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://example.com/revision?start_revid=[[r2]]#[[file]]-s",
+ description => "url to view a diff, using loggerhead ([[file]] and [[r2]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub bzr_log ($) {
+ my $out = shift;
+ my @infos = ();
+ my $key = undef;
+
+ while (<$out>) {
+ my $line = $_;
+ my ($value);
+ if ($line =~ /^message:/) {
+ $key = "message";
+ $infos[$#infos]{$key} = "";
+ }
+ elsif ($line =~ /^(modified|added|renamed|renamed and modified|removed):/) {
+ $key = "files";
+ unless (defined($infos[$#infos]{$key})) { $infos[$#infos]{$key} = ""; }
+ }
+ elsif (defined($key) and $line =~ /^ (.*)/) {
+ $infos[$#infos]{$key} .= "$1\n";
+ }
+ elsif ($line eq "------------------------------------------------------------\n") {
+ $key = undef;
+ push (@infos, {});
+ }
+ else {
+ chomp $line;
+ ($key, $value) = split /: +/, $line, 2;
+ $infos[$#infos]{$key} = $value;
+ }
+ }
+ close $out;
+
+ return @infos;
+}
+
+sub rcs_update () {
+ my @cmdline = ("bzr", "update", "--quiet", $config{srcdir});
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+}
+
+sub rcs_prepedit ($) {
+ return "";
+}
+
+sub bzr_author ($$) {
+ my ($user, $ipaddr) = @_;
+
+ if (defined $user) {
+ return IkiWiki::possibly_foolish_untaint($user);
+ }
+ elsif (defined $ipaddr) {
+ return "Anonymous from ".IkiWiki::possibly_foolish_untaint($ipaddr);
+ }
+ else {
+ return "Anonymous";
+ }
+}
+
+sub rcs_commit ($$$;$$) {
+ my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+
+ $user = bzr_author($user, $ipaddr);
+
+ $message = IkiWiki::possibly_foolish_untaint($message);
+ if (! length $message) {
+ $message = "no message given";
+ }
+
+ my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
+ $config{srcdir}."/".$file);
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+
+ return undef; # success
+}
+
+sub rcs_commit_staged ($$$) {
+ # Commits all staged changes. Changes can be staged using rcs_add,
+ # rcs_remove, and rcs_rename.
+ my ($message, $user, $ipaddr)=@_;
+
+ $user = bzr_author($user, $ipaddr);
+
+ $message = IkiWiki::possibly_foolish_untaint($message);
+ if (! length $message) {
+ $message = "no message given";
+ }
+
+ my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
+ $config{srcdir});
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+
+ return undef; # success
+}
+
+sub rcs_add ($) {
+ my ($file) = @_;
+
+ my @cmdline = ("bzr", "add", "--quiet", "$config{srcdir}/$file");
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+}
+
+sub rcs_remove ($) {
+ my ($file) = @_;
+
+ my @cmdline = ("bzr", "rm", "--force", "--quiet", "$config{srcdir}/$file");
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+}
+
+sub rcs_rename ($$) {
+ my ($src, $dest) = @_;
+
+ my $parent = IkiWiki::dirname($dest);
+ if (system("bzr", "add", "--quiet", "$config{srcdir}/$parent") != 0) {
+ warn("bzr add $parent failed\n");
+ }
+
+ my @cmdline = ("bzr", "mv", "--quiet", "$config{srcdir}/$src", "$config{srcdir}/$dest");
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+}
+
+sub rcs_recentchanges ($) {
+ my ($num) = @_;
+
+ my @cmdline = ("bzr", "log", "-v", "--show-ids", "--limit", $num,
+ $config{srcdir});
+ open (my $out, "@cmdline |");
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+
+ my @ret;
+ foreach my $info (bzr_log($out)) {
+ my @pages = ();
+ my @message = ();
+
+ foreach my $msgline (split(/\n/, $info->{message})) {
+ push @message, { line => $msgline };
+ }
+
+ foreach my $file (split(/\n/, $info->{files})) {
+ my ($filename, $fileid) = ($file =~ /^(.*?) +([^ ]+)$/);
+
+ # Skip directories
+ next if ($filename =~ /\/$/);
+
+ # Skip source name in renames
+ $filename =~ s/^.* => //;
+
+ my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : "";
+ $diffurl =~ s/\[\[file\]\]/$filename/go;
+ $diffurl =~ s/\[\[file-id\]\]/$fileid/go;
+ $diffurl =~ s/\[\[r2\]\]/$info->{revno}/go;
+
+ push @pages, {
+ page => pagename($filename),
+ diffurl => $diffurl,
+ };
+ }
+
+ my $user = $info->{"committer"};
+ if (defined($info->{"author"})) { $user = $info->{"author"}; }
+ $user =~ s/\s*<.*>\s*$//;
+ $user =~ s/^\s*//;
+
+ push @ret, {
+ rev => $info->{"revno"},
+ user => $user,
+ committype => "bzr",
+ when => str2time($info->{"timestamp"}),
+ message => [@message],
+ pages => [@pages],
+ };
+ }
+
+ return @ret;
+}
+
+sub rcs_diff ($) {
+ my $taintedrev=shift;
+ my ($rev) = $taintedrev =~ /^(\d+(\.\d+)*)$/; # untaint
+
+ my $prevspec = "before:" . $rev;
+ my $revspec = "revno:" . $rev;
+ my @cmdline = ("bzr", "diff", "--old", $config{srcdir},
+ "--new", $config{srcdir},
+ "-r", $prevspec . ".." . $revspec);
+ open (my $out, "@cmdline |");
+
+ my @lines = <$out>;
+ if (wantarray) {
+ return @lines;
+ }
+ else {
+ return join("", @lines);
+ }
+}
+
+sub rcs_getctime ($) {
+ my ($file) = @_;
+
+ # XXX filename passes through the shell here, should try to avoid
+ # that just in case
+ my @cmdline = ("bzr", "log", "--limit", '1', "$config{srcdir}/$file");
+ open (my $out, "@cmdline |");
+
+ my @log = bzr_log($out);
+
+ if (length @log < 1) {
+ return 0;
+ }
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+
+ my $ctime = str2time($log[0]->{"timestamp"});
+ return $ctime;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use Time::Local;
use POSIX;
my $time=time;
my @now=localtime($time);
-sub import { #{{{
- hook(type => "needsbuild", id => "version", call => \&needsbuild);
+sub import {
+ hook(type => "getsetup", id => "calendar", call => \&getsetup);
+ hook(type => "needsbuild", id => "calendar", call => \&needsbuild);
hook(type => "preprocess", id => "calendar", call => \&preprocess);
-} #}}}
-
-sub is_leap_year (@) { #{{{
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ archivebase => {
+ type => "string",
+ example => "archives",
+ description => "base of the archives hierarchy",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub is_leap_year (@) {
my %params=@_;
return ($params{year} % 4 == 0 && (($params{year} % 100 != 0) || $params{year} % 400 == 0));
-} #}}}
+}
-sub month_days { #{{{
+sub month_days {
my %params=@_;
my $days_in_month = (31,28,31,30,31,30,31,31,30,31,30,31)[$params{month}-1];
if ($params{month} == 2 && is_leap_year(%params)) {
$days_in_month++;
}
return $days_in_month;
-} #}}}
+}
-sub format_month (@) { #{{{
+sub format_month (@) {
my %params=@_;
my $pagespec = $params{pages};
# matching the pagespec are added or removed.
add_depends($params{page}, $params{pages});
# Explicitly add all currently linked pages as dependencies, so
- # that if they are removed, the calendar will be sure to be updated.
- add_depends($params{page}, join(" or ", @list));
+ # that if they are removed, the calendar will be sure to be updated.
+ foreach my $p (@list) {
+ add_depends($params{page}, $p);
+ }
return $calendar;
-} #}}}
+}
-sub format_year (@) { #{{{
+sub format_year (@) {
my %params=@_;
my $pagespec = $params{pages};
EOF
return $calendar;
-} #}}}
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
$params{pages} = "*" unless defined $params{pages};
$params{type} = "month" unless defined $params{type};
my $page =$params{page};
if (! defined $cache{$pagespec}) {
- foreach my $p (keys %pagesources) {
- next unless pagespec_match($p, $pagespec);
+ foreach my $p (pagespec_match_list([keys %pagesources], $pagespec)) {
my $mtime = $IkiWiki::pagectime{$p};
my $src = $pagesources{$p};
my @date = localtime($mtime);
return "\n<div><div class=\"calendar\">$calendar</div></div>\n";
} #}}
-sub needsbuild (@) { #{{{
+sub needsbuild (@) {
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
if (exists $pagestate{$page}{calendar}{nextchange}) {
}
}
}
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
# This regexp is based on the one in Text::WikiFormat.
my $link_regexp=qr{
)
}x;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "camelcase", call => \&getsetup);
hook(type => "linkify", id => "camelcase", call => \&linkify);
hook(type => "scan", id => "camelcase", call => \&scan);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ camelcase_ignore => {
+ type => "string",
+ example => [],
+ description => "list of words to not turn into links",
+ safe => 1,
+ rebuild => undef, # might change links
+ },
+}
-sub linkify (@) { #{{{
+sub linkify (@) {
my %params=@_;
my $page=$params{page};
my $destpage=$params{destpage};
$params{content}=~s{$link_regexp}{
- htmllink($page, $destpage, IkiWiki::linkpage($1))
+ ignored($1) ? $1 : htmllink($page, $destpage, linkpage($1))
}eg;
return $params{content};
-} #}}}
+}
-sub scan (@) { #{{{
+sub scan (@) {
my %params=@_;
my $page=$params{page};
my $content=$params{content};
while ($content =~ /$link_regexp/g) {
- push @{$links{$page}}, IkiWiki::linkpage($1);
+ add_link($page, linkpage($1)) unless ignored($1)
}
}
+sub ignored ($) {
+ my $word=lc shift;
+ grep { $word eq lc $_ } @{$config{'camelcase_ignore'}}
+}
+
1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki text colouring plugin
+# Paweł‚ Tęcza <ptecza@net.icm.edu.pl>
+package IkiWiki::Plugin::color;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "preprocess", id => "color", call => \&preprocess);
+ hook(type => "format", id => "color", call => \&format);
+}
+
+sub preserve_style ($$$) {
+ my $foreground = shift;
+ my $background = shift;
+ my $text = shift;
+
+ $foreground = defined $foreground ? lc($foreground) : '';
+ $background = defined $background ? lc($background) : '';
+ $text = '' unless (defined $text);
+
+ # Validate colors. Only color name or color code are valid.
+ $foreground = '' unless ($foreground &&
+ ($foreground =~ /^[a-z]+$/ || $foreground =~ /^#[0-9a-f]{3,6}$/));
+ $background = '' unless ($background &&
+ ($background =~ /^[a-z]+$/ || $background =~ /^#[0-9a-f]{3,6}$/));
+
+ my $preserved = '';
+ $preserved .= '<span class="color">';
+ $preserved .= 'color: '.$foreground if ($foreground);
+ $preserved .= '; ' if ($foreground && $background);
+ $preserved .= 'background-color: '.$background if ($background);
+ $preserved .= '</span>';
+ $preserved .= '<span class="colorend">'.$text.'</span>';
+
+ return $preserved;
+
+}
+
+sub replace_preserved_style ($) {
+ my $content = shift;
+
+ $content =~ s!<span class="color">((color: ([a-z]+|\#[0-9a-f]{3,6})?)?((; )?(background-color: ([a-z]+|\#[0-9a-f]{3,6})?)?)?)</span>!<span class="color" style="$1">!g;
+ $content =~ s!<span class="colorend">!!g;
+
+ return $content;
+}
+
+sub preprocess (@) {
+ my %params = @_;
+
+ # Preprocess the text to expand any preprocessor directives
+ # embedded inside it.
+ $params{text} = IkiWiki::preprocess($params{page}, $params{destpage},
+ IkiWiki::filter($params{page}, $params{destpage}, $params{text}));
+
+ return preserve_style($params{foreground}, $params{background}, $params{text});
+}
+
+sub format (@) {
+ my %params = @_;
+
+ $params{content} = replace_preserved_style($params{content});
+ return $params{content};
+}
+
+1
--- /dev/null
+#!/usr/bin/perl
+# Copyright © 2006-2008 Joey Hess <joey@ikiwiki.info>
+# Copyright © 2008 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+# Licensed under the GNU GPL, version 2, or any later version published by the
+# Free Software Foundation
+package IkiWiki::Plugin::comments;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use Encode;
+use POSIX qw(strftime);
+
+use constant PREVIEW => "Preview";
+use constant POST_COMMENT => "Post comment";
+use constant CANCEL => "Cancel";
+
+my $postcomment;
+my %commentstate;
+
+sub import {
+ hook(type => "checkconfig", id => 'comments', call => \&checkconfig);
+ hook(type => "getsetup", id => 'comments', call => \&getsetup);
+ hook(type => "preprocess", id => 'comment', call => \&preprocess);
+ # here for backwards compatability with old comments
+ hook(type => "preprocess", id => '_comment', call => \&preprocess);
+ hook(type => "sessioncgi", id => 'comment', call => \&sessioncgi);
+ hook(type => "htmlize", id => "_comment", call => \&htmlize);
+ hook(type => "pagetemplate", id => "comments", call => \&pagetemplate);
+ hook(type => "formbuilder_setup", id => "comments", call => \&formbuilder_setup);
+ # Load goto to fix up user page links for logged-in commenters
+ IkiWiki::loadplugin("goto");
+ IkiWiki::loadplugin("inline");
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ comments_pagespec => {
+ type => 'pagespec',
+ example => 'blog/* and !*/Discussion',
+ description => 'PageSpec of pages where comments are allowed',
+ link => 'ikiwiki/PageSpec',
+ safe => 1,
+ rebuild => 1,
+ },
+ comments_closed_pagespec => {
+ type => 'pagespec',
+ example => 'blog/controversial or blog/flamewar',
+ description => 'PageSpec of pages where posting new comments is not allowed',
+ link => 'ikiwiki/PageSpec',
+ safe => 1,
+ rebuild => 1,
+ },
+ comments_pagename => {
+ type => 'string',
+ default => 'comment_',
+ description => 'Base name for comments, e.g. "comment_" for pages like "sandbox/comment_12"',
+ safe => 0, # manual page moving required
+ rebuild => undef,
+ },
+ comments_allowdirectives => {
+ type => 'boolean',
+ example => 0,
+ description => 'Interpret directives in comments?',
+ safe => 1,
+ rebuild => 0,
+ },
+ comments_allowauthor => {
+ type => 'boolean',
+ example => 0,
+ description => 'Allow anonymous commenters to set an author name?',
+ safe => 1,
+ rebuild => 0,
+ },
+ comments_commit => {
+ type => 'boolean',
+ example => 1,
+ description => 'commit comments to the VCS',
+ # old uncommitted comments are likely to cause
+ # confusion if this is changed
+ safe => 0,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
+ $config{comments_commit} = 1
+ unless defined $config{comments_commit};
+ $config{comments_pagespec} = ''
+ unless defined $config{comments_pagespec};
+ $config{comments_closed_pagespec} = ''
+ unless defined $config{comments_closed_pagespec};
+ $config{comments_pagename} = 'comment_'
+ unless defined $config{comments_pagename};
+}
+
+sub htmlize {
+ my %params = @_;
+ return $params{content};
+}
+
+# FIXME: copied verbatim from meta
+sub safeurl ($) {
+ my $url=shift;
+ if (exists $IkiWiki::Plugin::htmlscrubber::{safe_url_regexp} &&
+ defined $IkiWiki::Plugin::htmlscrubber::safe_url_regexp) {
+ return $url=~/$IkiWiki::Plugin::htmlscrubber::safe_url_regexp/;
+ }
+ else {
+ return 1;
+ }
+}
+
+sub preprocess {
+ my %params = @_;
+ my $page = $params{page};
+
+ my $format = $params{format};
+ if (defined $format && ! exists $IkiWiki::hooks{htmlize}{$format}) {
+ error(sprintf(gettext("unsupported page format %s"), $format));
+ }
+
+ my $content = $params{content};
+ if (! defined $content) {
+ error(gettext("comment must have content"));
+ }
+ $content =~ s/\\"/"/g;
+
+ $content = IkiWiki::filter($page, $params{destpage}, $content);
+
+ if ($config{comments_allowdirectives}) {
+ $content = IkiWiki::preprocess($page, $params{destpage},
+ $content);
+ }
+
+ # no need to bother with htmlize if it's just HTML
+ $content = IkiWiki::htmlize($page, $params{destpage}, $format, $content)
+ if defined $format;
+
+ IkiWiki::run_hooks(sanitize => sub {
+ $content = shift->(
+ page => $page,
+ destpage => $params{destpage},
+ content => $content,
+ );
+ });
+
+ # set metadata, possibly overriding [[!meta]] directives from the
+ # comment itself
+
+ my $commentuser;
+ my $commentip;
+ my $commentauthor;
+ my $commentauthorurl;
+ my $commentopenid;
+ if (defined $params{username}) {
+ $commentuser = $params{username};
+
+ my $oiduser = eval { IkiWiki::openiduser($commentuser) };
+
+ if (defined $oiduser) {
+ # looks like an OpenID
+ $commentauthorurl = $commentuser;
+ $commentauthor = $oiduser;
+ $commentopenid = $commentuser;
+ }
+ else {
+ $commentauthorurl = IkiWiki::cgiurl(
+ do => 'goto',
+ page => (length $config{userdir}
+ ? "$config{userdir}/$commentuser"
+ : "$commentuser"));
+
+ $commentauthor = $commentuser;
+ }
+ }
+ else {
+ if (defined $params{ip}) {
+ $commentip = $params{ip};
+ }
+ $commentauthor = gettext("Anonymous");
+ }
+
+ $commentstate{$page}{commentuser} = $commentuser;
+ $commentstate{$page}{commentopenid} = $commentopenid;
+ $commentstate{$page}{commentip} = $commentip;
+ $commentstate{$page}{commentauthor} = $commentauthor;
+ $commentstate{$page}{commentauthorurl} = $commentauthorurl;
+ if (! defined $pagestate{$page}{meta}{author}) {
+ $pagestate{$page}{meta}{author} = $commentauthor;
+ }
+ if (! defined $pagestate{$page}{meta}{authorurl}) {
+ $pagestate{$page}{meta}{authorurl} = $commentauthorurl;
+ }
+
+ if ($config{comments_allowauthor}) {
+ if (defined $params{claimedauthor}) {
+ $pagestate{$page}{meta}{author} = $params{claimedauthor};
+ }
+
+ if (defined $params{url}) {
+ my $url=$params{url};
+
+ eval q{use URI::Heuristic};
+ if (! $@) {
+ $url=URI::Heuristic::uf_uristr($url);
+ }
+
+ if (safeurl($url)) {
+ $pagestate{$page}{meta}{authorurl} = $url;
+ }
+ }
+ }
+ else {
+ $pagestate{$page}{meta}{author} = $commentauthor;
+ $pagestate{$page}{meta}{authorurl} = $commentauthorurl;
+ }
+
+ if (defined $params{subject}) {
+ $pagestate{$page}{meta}{title} = $params{subject};
+ }
+
+ if ($params{page} =~ m/\/(\Q$config{comments_pagename}\E\d+)$/) {
+ $pagestate{$page}{meta}{permalink} = urlto(IkiWiki::dirname($params{page}), undef, 1).
+ "#".page_to_id($params{page});
+ }
+
+ eval q{use Date::Parse};
+ if (! $@) {
+ my $time = str2time($params{date});
+ $IkiWiki::pagectime{$page} = $time if defined $time;
+ }
+
+ return $content;
+}
+
+sub sessioncgi ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ my $do = $cgi->param('do');
+ if ($do eq 'comment') {
+ editcomment($cgi, $session);
+ }
+ elsif ($do eq 'commentmoderation') {
+ commentmoderation($cgi, $session);
+ }
+}
+
+# Mostly cargo-culted from IkiWiki::plugin::editpage
+sub editcomment ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ IkiWiki::decode_cgi_utf8($cgi);
+
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+
+ my @buttons = (POST_COMMENT, PREVIEW, CANCEL);
+ my $form = CGI::FormBuilder->new(
+ fields => [qw{do sid page subject editcontent type author url}],
+ charset => 'utf-8',
+ method => 'POST',
+ required => [qw{editcontent}],
+ javascript => 0,
+ params => $cgi,
+ action => $config{cgiurl},
+ header => 0,
+ table => 0,
+ template => scalar IkiWiki::template_params('editcomment.tmpl'),
+ );
+
+ IkiWiki::decode_form_utf8($form);
+ IkiWiki::run_hooks(formbuilder_setup => sub {
+ shift->(title => "comment", form => $form, cgi => $cgi,
+ session => $session, buttons => \@buttons);
+ });
+ IkiWiki::decode_form_utf8($form);
+
+ my $type = $form->param('type');
+ if (defined $type && length $type && $IkiWiki::hooks{htmlize}{$type}) {
+ $type = IkiWiki::possibly_foolish_untaint($type);
+ }
+ else {
+ $type = $config{default_pageext};
+ }
+
+
+ my @page_types;
+ if (exists $IkiWiki::hooks{htmlize}) {
+ foreach my $key (grep { !/^_/ } keys %{$IkiWiki::hooks{htmlize}}) {
+ push @page_types, [$key, $IkiWiki::hooks{htmlize}{$key}{longname} || $key];
+ }
+ }
+ @page_types=sort @page_types;
+
+ $form->field(name => 'do', type => 'hidden');
+ $form->field(name => 'sid', type => 'hidden', value => $session->id,
+ force => 1);
+ $form->field(name => 'page', type => 'hidden');
+ $form->field(name => 'subject', type => 'text', size => 72);
+ $form->field(name => 'editcontent', type => 'textarea', rows => 10);
+ $form->field(name => "type", value => $type, force => 1,
+ type => 'select', options => \@page_types);
+
+ $form->tmpl_param(username => $session->param('name'));
+
+ if ($config{comments_allowauthor} and
+ ! defined $session->param('name')) {
+ $form->tmpl_param(allowauthor => 1);
+ $form->field(name => 'author', type => 'text', size => '40');
+ $form->field(name => 'url', type => 'text', size => '40');
+ }
+ else {
+ $form->tmpl_param(allowauthor => 0);
+ $form->field(name => 'author', type => 'hidden', value => '',
+ force => 1);
+ $form->field(name => 'url', type => 'hidden', value => '',
+ force => 1);
+ }
+
+ if (! defined $session->param('name')) {
+ # Make signinurl work and return here.
+ $form->tmpl_param(signinurl => IkiWiki::cgiurl(do => 'signin'));
+ $session->param(postsignin => $ENV{QUERY_STRING});
+ IkiWiki::cgi_savesession($session);
+ }
+
+ # The untaint is OK (as in editpage) because we're about to pass
+ # it to file_pruned anyway
+ my $page = $form->field('page');
+ $page = IkiWiki::possibly_foolish_untaint($page);
+ if (! defined $page || ! length $page ||
+ IkiWiki::file_pruned($page, $config{srcdir})) {
+ error(gettext("bad page name"));
+ }
+
+ my $baseurl = urlto($page, undef, 1);
+
+ $form->title(sprintf(gettext("commenting on %s"),
+ IkiWiki::pagetitle($page)));
+
+ $form->tmpl_param('helponformattinglink',
+ htmllink($page, $page, 'ikiwiki/formatting',
+ noimageinline => 1,
+ linktext => 'FormattingHelp'),
+ allowdirectives => $config{allow_directives});
+
+ if ($form->submitted eq CANCEL) {
+ # bounce back to the page they wanted to comment on, and exit.
+ # CANCEL need not be considered in future
+ IkiWiki::redirect($cgi, urlto($page, undef, 1));
+ exit;
+ }
+
+ if (not exists $pagesources{$page}) {
+ error(sprintf(gettext(
+ "page '%s' doesn't exist, so you can't comment"),
+ $page));
+ }
+
+ if (pagespec_match($page, $config{comments_closed_pagespec},
+ location => $page)) {
+ error(sprintf(gettext(
+ "comments on page '%s' are closed"),
+ $page));
+ }
+
+ # Set a flag to indicate that we're posting a comment,
+ # so that postcomment() can tell it should match.
+ $postcomment=1;
+ IkiWiki::check_canedit($page, $cgi, $session);
+ $postcomment=0;
+
+ my $location=unique_comment_location($page, $config{srcdir});
+
+ my $content = "[[!comment format=$type\n";
+
+ # FIXME: handling of double quotes probably wrong?
+ if (defined $session->param('name')) {
+ my $username = $session->param('name');
+ $username =~ s/"/"/g;
+ $content .= " username=\"$username\"\n";
+ }
+ elsif (defined $ENV{REMOTE_ADDR}) {
+ my $ip = $ENV{REMOTE_ADDR};
+ if ($ip =~ m/^([.0-9]+)$/) {
+ $content .= " ip=\"$1\"\n";
+ }
+ }
+
+ if ($config{comments_allowauthor}) {
+ my $author = $form->field('author');
+ if (defined $author && length $author) {
+ $author =~ s/"/"/g;
+ $content .= " claimedauthor=\"$author\"\n";
+ }
+ my $url = $form->field('url');
+ if (defined $url && length $url) {
+ $url =~ s/"/"/g;
+ $content .= " url=\"$url\"\n";
+ }
+ }
+
+ my $subject = $form->field('subject');
+ if (defined $subject && length $subject) {
+ $subject =~ s/"/"/g;
+ $content .= " subject=\"$subject\"\n";
+ }
+
+ $content .= " date=\"" . decode_utf8(strftime('%Y-%m-%dT%H:%M:%SZ', gmtime)) . "\"\n";
+
+ my $editcontent = $form->field('editcontent') || '';
+ $editcontent =~ s/\r\n/\n/g;
+ $editcontent =~ s/\r/\n/g;
+ $editcontent =~ s/"/\\"/g;
+ $content .= " content=\"\"\"\n$editcontent\n\"\"\"]]\n";
+
+ # This is essentially a simplified version of editpage:
+ # - the user does not control the page that's created, only the parent
+ # - it's always a create operation, never an edit
+ # - this means that conflicts should never happen
+ # - this means that if they do, rocks fall and everyone dies
+
+ if ($form->submitted eq PREVIEW) {
+ my $preview=previewcomment($content, $location, $page, time);
+ IkiWiki::run_hooks(format => sub {
+ $preview = shift->(page => $page,
+ content => $preview);
+ });
+ $form->tmpl_param(page_preview => $preview);
+ }
+ else {
+ $form->tmpl_param(page_preview => "");
+ }
+
+ if ($form->submitted eq POST_COMMENT && $form->validate) {
+ IkiWiki::checksessionexpiry($cgi, $session);
+
+ $postcomment=1;
+ my $ok=IkiWiki::check_content(content => $form->field('editcontent'),
+ subject => $form->field('subject'),
+ $config{comments_allowauthor} ? (
+ author => $form->field('author'),
+ url => $form->field('url'),
+ ) : (),
+ page => $location,
+ cgi => $cgi,
+ session => $session,
+ nonfatal => 1,
+ );
+ $postcomment=0;
+
+ if (! $ok) {
+ my $penddir=$config{wikistatedir}."/comments_pending";
+ $location=unique_comment_location($page, $penddir);
+ writefile("$location._comment", $penddir, $content);
+ IkiWiki::printheader($session);
+ print IkiWiki::misctemplate(gettext(gettext("comment stored for moderation")),
+ "<p>".
+ gettext("Your comment will be posted after moderator review").
+ "</p>");
+ exit;
+ }
+
+ # FIXME: could probably do some sort of graceful retry
+ # on error? Would require significant unwinding though
+ my $file = "$location._comment";
+ writefile($file, $config{srcdir}, $content);
+
+ my $conflict;
+
+ if ($config{rcs} and $config{comments_commit}) {
+ my $message = gettext("Added a comment");
+ if (defined $form->field('subject') &&
+ length $form->field('subject')) {
+ $message = sprintf(
+ gettext("Added a comment: %s"),
+ $form->field('subject'));
+ }
+
+ IkiWiki::rcs_add($file);
+ IkiWiki::disable_commit_hook();
+ $conflict = IkiWiki::rcs_commit_staged($message,
+ $session->param('name'), $ENV{REMOTE_ADDR});
+ IkiWiki::enable_commit_hook();
+ IkiWiki::rcs_update();
+ }
+
+ # Now we need a refresh
+ require IkiWiki::Render;
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+
+ # this should never happen, unless a committer deliberately
+ # breaks it or something
+ error($conflict) if defined $conflict;
+
+ # Jump to the new comment on the page.
+ # The trailing question mark tries to avoid broken
+ # caches and get the most recent version of the page.
+ IkiWiki::redirect($cgi, urlto($page, undef, 1).
+ "?updated#".page_to_id($location));
+
+ }
+ else {
+ IkiWiki::showform ($form, \@buttons, $session, $cgi,
+ forcebaseurl => $baseurl);
+ }
+
+ exit;
+}
+
+sub commentmoderation ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ IkiWiki::needsignin($cgi, $session);
+ if (! IkiWiki::is_admin($session->param("name"))) {
+ error(gettext("you are not logged in as an admin"));
+ }
+
+ IkiWiki::decode_cgi_utf8($cgi);
+
+ if (defined $cgi->param('sid')) {
+ IkiWiki::checksessionexpiry($cgi, $session);
+
+ my $rejectalldefer=$cgi->param('rejectalldefer');
+
+ my %vars=$cgi->Vars;
+ my $added=0;
+ foreach my $id (keys %vars) {
+ if ($id =~ /(.*)\Q._comment\E$/) {
+ my $action=$cgi->param($id);
+ next if $action eq 'Defer' && ! $rejectalldefer;
+
+ # Make sure that the id is of a legal
+ # pending comment before untainting.
+ my ($f)= $id =~ /$config{wiki_file_regexp}/;
+ if (! defined $f || ! length $f ||
+ IkiWiki::file_pruned($f, $config{srcdir})) {
+ error("illegal file");
+ }
+
+ my $page=IkiWiki::possibly_foolish_untaint(IkiWiki::dirname($1));
+ my $file="$config{wikistatedir}/comments_pending/".
+ IkiWiki::possibly_foolish_untaint($id);
+
+ if ($action eq 'Accept') {
+ my $content=eval { readfile($file) };
+ next if $@; # file vanished since form was displayed
+ my $dest=unique_comment_location($page, $config{srcdir})."._comment";
+ writefile($dest, $config{srcdir}, $content);
+ if ($config{rcs} and $config{comments_commit}) {
+ IkiWiki::rcs_add($dest);
+ }
+ $added++;
+ }
+
+ # This removes empty subdirs, so the
+ # .ikiwiki/comments_pending dir will
+ # go away when all are moderated.
+ require IkiWiki::Render;
+ IkiWiki::prune($file);
+ }
+ }
+
+ if ($added) {
+ my $conflict;
+ if ($config{rcs} and $config{comments_commit}) {
+ my $message = gettext("Comment moderation");
+ IkiWiki::disable_commit_hook();
+ $conflict=IkiWiki::rcs_commit_staged($message,
+ $session->param('name'), $ENV{REMOTE_ADDR});
+ IkiWiki::enable_commit_hook();
+ IkiWiki::rcs_update();
+ }
+
+ # Now we need a refresh
+ require IkiWiki::Render;
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+
+ error($conflict) if defined $conflict;
+ }
+ }
+
+ my @comments=map {
+ my ($id, $ctime)=@{$_};
+ my $file="$config{wikistatedir}/comments_pending/$id";
+ my $content=readfile($file);
+ my $preview=previewcomment($content, $id,
+ IkiWiki::dirname($_), $ctime);
+ {
+ id => $id,
+ view => $preview,
+ }
+ } sort { $b->[1] <=> $a->[1] } comments_pending();
+
+ my $template=template("commentmoderation.tmpl");
+ $template->param(
+ sid => $session->id,
+ comments => \@comments,
+ );
+ IkiWiki::printheader($session);
+ my $out=$template->output;
+ IkiWiki::run_hooks(format => sub {
+ $out = shift->(page => "", content => $out);
+ });
+ print IkiWiki::misctemplate(gettext("comment moderation"), $out);
+ exit;
+}
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+
+ my $form=$params{form};
+ if ($form->title eq "preferences" &&
+ IkiWiki::is_admin($params{session}->param("name"))) {
+ push @{$params{buttons}}, "Comment Moderation";
+ if ($form->submitted && $form->submitted eq "Comment Moderation") {
+ commentmoderation($params{cgi}, $params{session});
+ }
+ }
+}
+
+sub comments_pending () {
+ my $dir="$config{wikistatedir}/comments_pending/";
+ return unless -d $dir;
+
+ my @ret;
+ eval q{use File::Find};
+ error($@) if $@;
+ find({
+ no_chdir => 1,
+ wanted => sub {
+ $_=decode_utf8($_);
+ if (IkiWiki::file_pruned($_, $dir)) {
+ $File::Find::prune=1;
+ }
+ elsif (! -l $_ && ! -d _) {
+ $File::Find::prune=0;
+ my ($f)=/$config{wiki_file_regexp}/; # untaint
+ if (defined $f && $f =~ /\Q._comment\E$/) {
+ my $ctime=(stat($f))[10];
+ $f=~s/^\Q$dir\E\/?//;
+ push @ret, [$f, $ctime];
+ }
+ }
+ }
+ }, $dir);
+
+ return @ret;
+}
+
+sub previewcomment ($$$) {
+ my $content=shift;
+ my $location=shift;
+ my $page=shift;
+ my $time=shift;
+
+ my $preview = IkiWiki::htmlize($location, $page, '_comment',
+ IkiWiki::linkify($location, $page,
+ IkiWiki::preprocess($location, $page,
+ IkiWiki::filter($location, $page, $content), 0, 1)));
+
+ my $template = template("comment.tmpl");
+ $template->param(content => $preview);
+ $template->param(ctime => displaytime($time));
+
+ IkiWiki::run_hooks(pagetemplate => sub {
+ shift->(page => $location,
+ destpage => $page,
+ template => $template);
+ });
+
+ $template->param(have_actions => 0);
+
+ return $template->output;
+}
+
+sub commentsshown ($) {
+ my $page=shift;
+
+ return ! pagespec_match($page, "internal(*/$config{comments_pagename}*)",
+ location => $page) &&
+ pagespec_match($page, $config{comments_pagespec},
+ location => $page);
+}
+
+sub commentsopen ($) {
+ my $page = shift;
+
+ return length $config{cgiurl} > 0 &&
+ (! length $config{comments_closed_pagespec} ||
+ ! pagespec_match($page, $config{comments_closed_pagespec},
+ location => $page));
+}
+
+sub pagetemplate (@) {
+ my %params = @_;
+
+ my $page = $params{page};
+ my $template = $params{template};
+ my $shown = ($template->query(name => 'commentslink') ||
+ $template->query(name => 'commentsurl') ||
+ $template->query(name => 'atomcommentsurl') ||
+ $template->query(name => 'comments')) &&
+ commentsshown($page);
+
+ if ($template->query(name => 'comments')) {
+ my $comments = undef;
+ if ($shown) {
+ $comments = IkiWiki::preprocess_inline(
+ pages => "internal($page/$config{comments_pagename}*)",
+ template => 'comment',
+ show => 0,
+ reverse => 'yes',
+ page => $page,
+ destpage => $params{destpage},
+ feedfile => 'comments',
+ emptyfeeds => 'no',
+ );
+ }
+
+ if (defined $comments && length $comments) {
+ $template->param(comments => $comments);
+ }
+
+ if ($shown && commentsopen($page)) {
+ my $addcommenturl = IkiWiki::cgiurl(do => 'comment',
+ page => $page);
+ $template->param(addcommenturl => $addcommenturl);
+ }
+ }
+
+ if ($template->query(name => 'commentsurl')) {
+ if ($shown) {
+ $template->param(commentsurl =>
+ urlto($page, undef, 1).'#comments');
+ }
+ }
+
+ if ($template->query(name => 'atomcommentsurl') && $config{usedirs}) {
+ if ($shown) {
+ # This will 404 until there are some comments, but I
+ # think that's probably OK...
+ $template->param(atomcommentsurl =>
+ urlto($page, undef, 1).'comments.atom');
+ }
+ }
+
+ if ($template->query(name => 'commentslink')) {
+ # XXX Would be nice to say how many comments there are in
+ # the link. But, to update the number, blog pages
+ # would have to update whenever comments of any inlines
+ # page are added, which is not currently done.
+ if ($shown) {
+ $template->param(commentslink =>
+ htmllink($page, $params{destpage}, $page,
+ linktext => gettext("Comments"),
+ anchor => "comments",
+ noimageinline => 1));
+ }
+ }
+
+ # everything below this point is only relevant to the comments
+ # themselves
+ if (!exists $commentstate{$page}) {
+ return;
+ }
+
+ if ($template->query(name => 'commentid')) {
+ $template->param(commentid => page_to_id($page));
+ }
+
+ if ($template->query(name => 'commentuser')) {
+ $template->param(commentuser =>
+ $commentstate{$page}{commentuser});
+ }
+
+ if ($template->query(name => 'commentopenid')) {
+ $template->param(commentopenid =>
+ $commentstate{$page}{commentopenid});
+ }
+
+ if ($template->query(name => 'commentip')) {
+ $template->param(commentip =>
+ $commentstate{$page}{commentip});
+ }
+
+ if ($template->query(name => 'commentauthor')) {
+ $template->param(commentauthor =>
+ $commentstate{$page}{commentauthor});
+ }
+
+ if ($template->query(name => 'commentauthorurl')) {
+ $template->param(commentauthorurl =>
+ $commentstate{$page}{commentauthorurl});
+ }
+
+ if ($template->query(name => 'removeurl') &&
+ IkiWiki::Plugin::remove->can("check_canremove") &&
+ length $config{cgiurl}) {
+ $template->param(removeurl => IkiWiki::cgiurl(do => 'remove',
+ page => $page));
+ $template->param(have_actions => 1);
+ }
+}
+
+sub unique_comment_location ($) {
+ my $page=shift;
+ my $dir=shift;
+
+ my $location;
+ my $i = 0;
+ do {
+ $i++;
+ $location = "$page/$config{comments_pagename}$i";
+ } while (-e "$dir/$location._comment");
+
+ return $location;
+}
+
+sub page_to_id ($) {
+ # Converts a comment page name into a unique, legal html id
+ # addtibute value, that can be used as an anchor to link to the
+ # comment.
+ my $page=shift;
+
+ eval q{use Digest::MD5 'md5_hex'};
+ error($@) if $@;
+
+ return "comment-".md5_hex($page);
+}
+
+package IkiWiki::PageSpec;
+
+sub match_postcomment ($$;@) {
+ my $page = shift;
+ my $glob = shift;
+
+ if (! $postcomment) {
+ return IkiWiki::FailReason->new("not posting a comment");
+ }
+ return match_glob($page, $glob);
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use UNIVERSAL;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "conditional", call => \&getsetup);
hook(type => "preprocess", id => "if", call => \&preprocess_if);
-} # }}}
+}
-sub preprocess_if (@) { #{{{
+sub getsetup {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess_if (@) {
my %params=@_;
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);
}
}
# An optimisation to avoid needless looping over every page
# and adding of dependencies for simple uses of some of the
# tests.
- $params{test} =~ /^\s*\!?\s*(enabled|sourcepage|destpage|included)\((.*)\)\s*$/) {
- add_depends($params{page}, "$params{test} and $params{page}");
+ $params{test} =~ /^([\s\!()]*((enabled|sourcepage|destpage|included)\([^)]*\)|(and|or))[\s\!()]*)+$/) {
+ add_depends($params{page}, "($params{test}) and $params{page}");
$result=pagespec_match($params{page}, $params{test},
location => $params{page},
sourcepage => $params{page},
}
return IkiWiki::preprocess($params{page}, $params{destpage},
IkiWiki::filter($params{page}, $params{destpage}, $ret));
-} # }}}
+}
package IkiWiki::PageSpec;
-sub match_enabled ($$;@) { #{{{
+sub match_enabled ($$;@) {
shift;
my $plugin=shift;
else {
return IkiWiki::FailReason->new("$plugin is not enabled");
}
-} #}}}
+}
-sub match_sourcepage ($$;@) { #{{{
+sub match_sourcepage ($$;@) {
shift;
my $glob=shift;
my %params=@_;
+
+ $glob=derel($glob, $params{location});
return IkiWiki::FailReason->new("cannot match sourcepage") unless exists $params{sourcepage};
if (match_glob($params{sourcepage}, $glob, @_)) {
else {
return IkiWiki::FailReason->new("sourcepage does not match $glob");
}
-} #}}}
+}
-sub match_destpage ($$;@) { #{{{
+sub match_destpage ($$;@) {
shift;
my $glob=shift;
my %params=@_;
+ $glob=derel($glob, $params{location});
+
return IkiWiki::FailReason->new("cannot match destpage") unless exists $params{destpage};
if (match_glob($params{destpage}, $glob, @_)) {
return IkiWiki::SuccessReason->new("destpage matches $glob");
else {
return IkiWiki::FailReason->new("destpage does not match $glob");
}
-} #}}}
+}
-sub match_included ($$;@) { #{{{
+sub match_included ($$;@) {
shift;
shift;
my %params=@_;
else {
return IkiWiki::FailReason->new("page $params{sourcepage} is not included");
}
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "creole", call => \&getsetup);
hook(type => "htmlize", id => "creole", call => \&htmlize);
-} # }}}
+}
-sub htmlize (@) { #{{{
+sub getsetup {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+}
+
+sub htmlize (@) {
my %params=@_;
my $content = $params{content};
creole_custombarelinks();
return creole_parse($content);
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::cutpaste;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+my %savedtext;
+
+sub import {
+ hook(type => "getsetup", id => "cutpaste", call => \&getsetup);
+ hook(type => "preprocess", id => "cut", call => \&preprocess_cut, scan => 1);
+ hook(type => "preprocess", id => "copy", call => \&preprocess_copy, scan => 1);
+ hook(type => "preprocess", id => "paste", call => \&preprocess_paste);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess_cut (@) {
+ my %params=@_;
+
+ foreach my $param (qw{id text}) {
+ if (! exists $params{$param}) {
+ error sprintf(gettext('%s parameter is required'), $param);
+ }
+ }
+
+ $savedtext{$params{page}} = {} if not exists $savedtext{$params{"page"}};
+ $savedtext{$params{page}}->{$params{id}} = $params{text};
+
+ return "" if defined wantarray;
+}
+
+sub preprocess_copy (@) {
+ my %params=@_;
+
+ foreach my $param (qw{id text}) {
+ if (! exists $params{$param}) {
+ error sprintf(gettext('%s parameter is required'), $param);
+ }
+ }
+
+ $savedtext{$params{page}} = {} if not exists $savedtext{$params{"page"}};
+ $savedtext{$params{page}}->{$params{id}} = $params{text};
+
+ return IkiWiki::preprocess($params{page}, $params{destpage},
+ IkiWiki::filter($params{page}, $params{destpage}, $params{text})) if defined wantarray;
+}
+
+sub preprocess_paste (@) {
+ my %params=@_;
+
+ foreach my $param (qw{id}) {
+ if (! exists $params{$param}) {
+ error sprintf(gettext('%s parameter is required'), $param);
+ }
+ }
+
+ if (! exists $savedtext{$params{page}}) {
+ error gettext('no text was copied in this page');
+ }
+ if (! exists $savedtext{$params{page}}->{$params{id}}) {
+ error sprintf(gettext('no text was copied in this page with id %s'), $params{id});
+ }
+
+ return IkiWiki::preprocess($params{page}, $params{destpage},
+ IkiWiki::filter($params{page}, $params{destpage}, $savedtext{$params{page}}->{$params{id}}));
+}
+
+1;
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::darcs;
+
+use warnings;
+use strict;
+use IkiWiki;
+
+sub import {
+ hook(type => "checkconfig", id => "darcs", call => \&checkconfig);
+ hook(type => "getsetup", id => "darcs", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub silentsystem (@) {
+ open(SAVED_STDOUT, ">&STDOUT");
+ open(STDOUT, ">/dev/null");
+ my $ret = system @_;
+ open(STDOUT, ">&SAVED_STDOUT");
+ return $ret;
+}
+
+sub darcs_info ($$$) {
+ my $field = shift;
+ my $repodir = shift;
+ my $file = shift; # Relative to the repodir.
+
+ my $child = open(DARCS_CHANGES, "-|");
+ if (! $child) {
+ exec('darcs', 'changes', '--repodir', $repodir, '--xml-output', $file) or
+ error("failed to run 'darcs changes'");
+ }
+
+ # Brute force for now. :-/
+ while (<DARCS_CHANGES>) {
+ last if /^<\/created_as>$/;
+ }
+ ($_) = <DARCS_CHANGES> =~ /$field=\'([^\']+)/;
+ $field eq 'hash' and s/\.gz//; # Strip away the '.gz' from 'hash'es.
+
+ close(DARCS_CHANGES);
+
+ return $_;
+}
+
+sub file_in_vc($$) {
+ my $repodir = shift;
+ my $file = shift;
+
+ my $child = open(DARCS_MANIFEST, "-|");
+ if (! $child) {
+ exec('darcs', 'query', 'manifest', '--repodir', $repodir) or
+ error("failed to run 'darcs query manifest'");
+ }
+ my $found=0;
+ while (<DARCS_MANIFEST>) {
+ $found = 1, last if /^(\.\/)?$file$/;
+ }
+ close(DARCS_MANIFEST) or error("'darcs query manifest' exited " . $?);
+
+ return $found;
+}
+
+sub darcs_rev($) {
+ my $file = shift; # Relative to the repodir.
+ my $repodir = $config{srcdir};
+
+ return "" if (! file_in_vc($repodir, $file));
+ my $hash = darcs_info('hash', $repodir, $file);
+ return defined $hash ? $hash : "";
+}
+
+sub checkconfig() {
+ if (defined $config{darcs_wrapper} && length $config{darcs_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{darcs_wrapper},
+ wrappermode => (defined $config{darcs_wrappermode} ? $config{darcs_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup() {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ darcs_wrapper => {
+ type => "string",
+ example => "/darcs/repo/_darcs/ikiwiki-wrapper",
+ description => "wrapper to generate (set as master repo apply hook)",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ darcs_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for darcs_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://darcs.example.com/darcsweb.cgi?r=wiki;a=filehistory;f=[[file]]",
+ description => "darcsweb url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://darcs.example.com/darcsweb.cgi?r=wiki;a=filediff;h=[[hash]];f=[[file]]",
+ description => "darcsweb url to show a diff ([[hash]] and [[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub rcs_update () {
+ silentsystem('darcs', "pull", "--repodir", $config{srcdir}, "-qa")
+}
+
+sub rcs_prepedit ($) {
+ # Prepares to edit a file under revision control. Returns a token that
+ # must be passed to rcs_commit() when the file is to be commited. For us,
+ # this token the hash value of the latest patch that modifies the file,
+ # i.e. something like its current revision.
+
+ my $file = shift; # Relative to the repodir.
+ my $rev = darcs_rev($file);
+ return $rev;
+}
+
+sub rcs_commit ($$$;$$) {
+ # Commit the page. Returns 'undef' on success and a version of the page
+ # with conflict markers on failure.
+
+ my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+
+ # Compute if the "revision" of $file changed.
+ my $changed = darcs_rev($file) ne $rcstoken;
+
+ # Yes, the following is a bit convoluted.
+ if ($changed) {
+ # TODO. Invent a better, non-conflicting name.
+ rename("$config{srcdir}/$file", "$config{srcdir}/$file.save") or
+ error("failed to rename $file to $file.save: $!");
+
+ # Roll the repository back to $rcstoken.
+
+ # TODO. Can we be sure that no changes are lost? I think that
+ # we can, if we make sure that the 'darcs push' below will always
+ # succeed.
+
+ # We need to revert everything as 'darcs obliterate' might choke
+ # otherwise.
+ # TODO: 'yes | ...' needed? Doesn't seem so.
+ silentsystem('darcs', "revert", "--repodir", $config{srcdir}, "--all") == 0 ||
+ error("'darcs revert' failed");
+ # Remove all patches starting at $rcstoken.
+ my $child = open(DARCS_OBLITERATE, "|-");
+ if (! $child) {
+ open(STDOUT, ">/dev/null");
+ exec('darcs', "obliterate", "--repodir", $config{srcdir},
+ "--match", "hash " . $rcstoken) and
+ error("'darcs obliterate' failed");
+ }
+ 1 while print DARCS_OBLITERATE "y";
+ close(DARCS_OBLITERATE);
+ # Restore the $rcstoken one.
+ silentsystem('darcs', "pull", "--quiet", "--repodir", $config{srcdir},
+ "--match", "hash " . $rcstoken, "--all") == 0 ||
+ error("'darcs pull' failed");
+
+ # We're back at $rcstoken. Re-install the modified file.
+ rename("$config{srcdir}/$file.save", "$config{srcdir}/$file") or
+ error("failed to rename $file.save to $file: $!");
+ }
+
+ # Record the changes.
+ my $author;
+ if (defined $user) {
+ $author = "$user\@web";
+ }
+ elsif (defined $ipaddr) {
+ $author = "$ipaddr\@web";
+ }
+ else {
+ $author = "anon\@web";
+ }
+ if (!defined $message || !length($message)) {
+ $message = "empty message";
+ }
+ silentsystem('darcs', 'record', '--repodir', $config{srcdir}, '--all',
+ '-m', $message, '--author', $author, $file) == 0 ||
+ error("'darcs record' failed");
+
+ # Update the repository by pulling from the default repository, which is
+ # master repository.
+ silentsystem('darcs', "pull", "--quiet", "--repodir", $config{srcdir},
+ "--all") == 0 || error("'darcs pull' failed");
+
+ # If this updating yields any conflicts, we'll record them now to resolve
+ # them. If nothing is recorded, there are no conflicts.
+ $rcstoken = darcs_rev($file);
+ # TODO: Use only the first line here, i.e. only the patch name?
+ writefile("$file.log", $config{srcdir}, 'resolve conflicts: ' . $message);
+ silentsystem('darcs', 'record', '--repodir', $config{srcdir}, '--all',
+ '-m', 'resolve conflicts: ' . $message, '--author', $author, $file) == 0 ||
+ error("'darcs record' failed");
+ my $conflicts = darcs_rev($file) ne $rcstoken;
+ unlink("$config{srcdir}/$file.log") or
+ error("failed to remove '$file.log'");
+
+ # Push the changes to the main repository.
+ silentsystem('darcs', 'push', '--quiet', '--repodir', $config{srcdir}, '--all') == 0 ||
+ error("'darcs push' failed");
+ # TODO: darcs send?
+
+ if ($conflicts) {
+ my $document = readfile("$config{srcdir}/$file");
+ # Try to leave everything in a consistent state.
+ # TODO: 'yes | ...' needed? Doesn't seem so.
+ silentsystem('darcs', "revert", "--repodir", $config{srcdir}, "--all") == 0 ||
+ warn("'darcs revert' failed");
+ return $document;
+ }
+ else {
+ return undef;
+ }
+}
+
+sub rcs_commit_staged($$$) {
+ my ($message, $user, $ipaddr) = @_;
+
+ my $author;
+ if (defined $user) {
+ $author = "$user\@web";
+ }
+ elsif (defined $ipaddr) {
+ $author = "$ipaddr\@web";
+ }
+ else {
+ $author = "anon\@web";
+ }
+ if (!defined $message || !length($message)) {
+ $message = "empty message";
+ }
+
+ silentsystem('darcs', "record", "--repodir", $config{srcdir}, "-a", "-A", $author,
+ "-m", $message) == 0 || error("'darcs record' failed");
+
+ # Push the changes to the main repository.
+ silentsystem('darcs', 'push', '--quiet', '--repodir', $config{srcdir}, '--all') == 0 ||
+ error("'darcs push' failed");
+ # TODO: darcs send?
+
+ return undef;
+}
+
+sub rcs_add ($) {
+ my $file = shift; # Relative to the repodir.
+
+ if(! file_in_vc($config{srcdir}, $file)) {
+ # Intermediate directories will be added automagically.
+ system('darcs', 'add', '--quiet', '--repodir', $config{srcdir},
+ '--boring', $file) == 0 || error("'darcs add' failed");
+ }
+}
+
+sub rcs_remove ($) {
+ my $file = shift; # Relative to the repodir.
+
+ unlink($config{srcdir}.'/'.$file);
+}
+
+sub rcs_rename ($$) {
+ my $a = shift; # Relative to the repodir.
+ my $b = shift; # Relative to the repodir.
+
+ system('darcs', 'mv', '--repodir', $config{srcdir}, $a, $b) == 0 ||
+ error("'darcs mv' failed");
+}
+
+sub rcs_recentchanges ($) {
+ my $num=shift;
+ my @ret;
+
+ eval q{use Date::Parse};
+ eval q{use XML::Simple};
+
+ my $repodir=$config{srcdir};
+
+ my $child = open(LOG, "-|");
+ if (! $child) {
+ $ENV{"DARCS_DONT_ESCAPE_ANYTHING"}=1;
+ exec("darcs", "changes", "--xml",
+ "--summary",
+ "--repodir", "$repodir",
+ "--last", "$num")
+ || error("'darcs changes' failed to run");
+ }
+ my $data;
+ $data .= $_ while(<LOG>);
+ close LOG;
+
+ my $log = XMLin($data, ForceArray => 1);
+
+ foreach my $patch (@{$log->{patch}}) {
+ my $date=$patch->{local_date};
+ my $hash=$patch->{hash};
+ my $when=str2time($date);
+ my (@pages, @files, @pg);
+ push @pages, $_ foreach (@{$patch->{summary}->[0]->{modify_file}});
+ push @pages, $_ foreach (@{$patch->{summary}->[0]->{add_file}});
+ push @pages, $_ foreach (@{$patch->{summary}->[0]->{remove_file}});
+ foreach my $f (@pages) {
+ $f = $f->{content} if ref $f;
+ $f =~ s,^\s+,,; $f =~ s,\s+$,,; # cut whitespace
+
+ push @files, $f;
+ }
+ foreach my $p (@{$patch->{summary}->[0]->{move}}) {
+ push @files, $p->{from};
+ }
+
+ foreach my $f (@files) {
+ my $d = defined $config{'diffurl'} ? $config{'diffurl'} : "";
+ $d =~ s/\[\[file\]\]/$f/go;
+ $d =~ s/\[\[hash\]\]/$hash/go;
+
+ push @pg, {
+ page => pagename($f),
+ diffurl => $d,
+ };
+ }
+ next unless (scalar @pg > 0);
+
+ my @message;
+ push @message, { line => $_ } foreach (@{$patch->{name}});
+
+ my $committype;
+ my $author;
+ if ($patch->{author} =~ /(.*)\@web$/) {
+ $author = $1;
+ $committype = "web";
+ }
+ else {
+ $author=$patch->{author};
+ $committype = "darcs";
+ }
+
+ push @ret, {
+ rev => $patch->{hash},
+ user => $author,
+ committype => $committype,
+ when => $when,
+ message => [@message],
+ pages => [@pg],
+ };
+ }
+
+ return @ret;
+}
+
+sub rcs_diff ($) {
+ my $rev=shift;
+ my @lines;
+ foreach my $line (silentsystem("darcs", "diff", "--match", "hash ".$rev)) {
+ if (@lines || $line=~/^diff/) {
+ push @lines, $line."\n";
+ }
+ }
+ if (wantarray) {
+ return @lines;
+ }
+ else {
+ return join("", @lines);
+ }
+}
+
+sub rcs_getctime ($) {
+ my $file=shift;
+
+ eval q{use Date::Parse};
+ eval q{use XML::Simple};
+ local $/=undef;
+
+ my $filer=substr($file, length($config{srcdir}));
+ $filer =~ s:^[/]+::;
+
+ my $child = open(LOG, "-|");
+ if (! $child) {
+ exec("darcs", "changes", "--xml", "--reverse",
+ "--repodir", $config{srcdir}, $filer)
+ || error("'darcs changes $filer' failed to run");
+ }
+
+ my $data;
+ {
+ local $/=undef;
+ $data = <LOG>;
+ }
+ close LOG;
+
+ my $log = XMLin($data, ForceArray => 1);
+
+ my $datestr = $log->{patch}[0]->{local_date};
+
+ if (! defined $datestr) {
+ warn "failed to get ctime for $filer";
+ return 0;
+ }
+
+ my $date = str2time($datestr);
+
+ debug("ctime for '$file': ". localtime($date));
+
+ return $date;
+}
+
+1
# Discordian date support fnord ikiwiki.
package IkiWiki::Plugin::ddate;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
no warnings;
-sub import { #{{{
- hook(type => "checkconfig", id => "ddate", call => \&checkconfig);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "ddate", call => \&getsetup);
+}
-sub checkconfig () { #{{{
- if (! defined $config{timeformat} ||
- $config{timeformat} eq '%c') {
- $config{timeformat}='on %A, the %e of %B, %Y. %N%nCelebrate %H';
- }
-} #}}}
+sub getsetup {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
-sub IkiWiki::displaytime ($;$) { #{{{
+sub IkiWiki::formattime ($;$) {
my $time=shift;
my $format=shift;
if (! defined $format) {
$format=$config{timeformat};
+ if ($format eq '%c') {
+ $format='on %A, the %e of %B, %Y. %N%nCelebrate %H';
+ }
}
eval q{
use DateTime;
my $dt = DateTime->from_epoch(epoch => $time);
my $dd = DateTime::Calendar::Discordian->from_object(object => $dt);
return $dd->strftime($format);
-} #}}}
+}
5
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use HTML::Entities;
use IPC::Open2;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "editdiff", call => \&getsetup);
hook(type => "formbuilder_setup", id => "editdiff",
call => \&formbuilder_setup);
-} #}}}
+}
-sub diff ($$) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub diff ($$) {
my $orig=shift;
my $content=shift;
return "couldn't run diff\n" if $sigpipe;
return "<pre>".encode_entities($ret)."</pre>";
-} #}}}
+}
-sub formbuilder_setup { #{{{
+sub formbuilder_setup {
my %params=@_;
my $form=$params{form};
- return if defined ! $form->field("do") || $form->field("do") ne "edit";
+ return if ! defined $form->field("do") || $form->field("do") ne "edit";
my $page=$form->field("page");
$page = IkiWiki::possibly_foolish_untaint($page);
my $diff = diff(srcfile($pagesources{$page}), $content);
$form->tmpl_param("page_preview", $diff);
}
-} #}}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::editpage;
+
+use warnings;
+use strict;
+use IkiWiki;
+use open qw{:utf8 :std};
+
+sub import {
+ hook(type => "getsetup", id => "editpage", call => \&getsetup);
+ hook(type => "refresh", id => "editpage", call => \&refresh);
+ hook(type => "sessioncgi", id => "editpage", call => \&IkiWiki::cgi_editpage);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub refresh () {
+ if (exists $wikistate{editpage} && exists $wikistate{editpage}{previews}) {
+ # Expire old preview files after one hour.
+ my $expire=time - (60 * 60);
+
+ my @previews;
+ foreach my $file (@{$wikistate{editpage}{previews}}) {
+ my $mtime=(stat("$config{destdir}/$file"))[9];
+ if (defined $mtime && $mtime <= $expire) {
+ # Avoid deleting a preview that was later saved.
+ my $delete=1;
+ foreach my $page (keys %renderedfiles) {
+ if (grep { $_ eq $file } @{$renderedfiles{$page}}) {
+ $delete=0;
+ }
+ }
+ if ($delete) {
+ debug(sprintf(gettext("removing old preview %s"), $file));
+ IkiWiki::prune("$config{destdir}/$file");
+ }
+ }
+ elsif (defined $mtime) {
+ push @previews, $file;
+ }
+ }
+ $wikistate{editpage}{previews}=\@previews;
+ }
+}
+
+# Back to ikiwiki namespace for the rest, this code is very much
+# internal to ikiwiki even though it's separated into a plugin,
+# and other plugins use the function below.
+package IkiWiki;
+
+sub cgi_editpage ($$) {
+ my $q=shift;
+ my $session=shift;
+
+ my $do=$q->param('do');
+ return unless $do eq 'create' || $do eq 'edit';
+
+ decode_cgi_utf8($q);
+
+ my @fields=qw(do rcsinfo subpage from page type editcontent comments);
+ my @buttons=("Save Page", "Preview", "Cancel");
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+ my $form = CGI::FormBuilder->new(
+ fields => \@fields,
+ charset => "utf-8",
+ method => 'POST',
+ required => [qw{editcontent}],
+ javascript => 0,
+ params => $q,
+ action => $config{cgiurl},
+ header => 0,
+ table => 0,
+ template => scalar template_params("editpage.tmpl"),
+ );
+
+ decode_form_utf8($form);
+ run_hooks(formbuilder_setup => sub {
+ shift->(form => $form, cgi => $q, session => $session,
+ buttons => \@buttons);
+ });
+ decode_form_utf8($form);
+
+ # This untaint is safe because we check file_pruned and
+ # wiki_file_regexp.
+ my ($page)=$form->field('page')=~/$config{wiki_file_regexp}/;
+ $page=possibly_foolish_untaint($page);
+ my $absolute=($page =~ s#^/+##);
+ if (! defined $page || ! length $page ||
+ file_pruned($page, $config{srcdir})) {
+ error(gettext("bad page name"));
+ }
+
+ my $baseurl = urlto($page, undef, 1);
+
+ my $from;
+ if (defined $form->field('from')) {
+ ($from)=$form->field('from')=~/$config{wiki_file_regexp}/;
+ }
+
+ my $file;
+ my $type;
+ if (exists $pagesources{$page} && $form->field("do") ne "create") {
+ $file=$pagesources{$page};
+ $type=pagetype($file);
+ if (! defined $type || $type=~/^_/) {
+ error(sprintf(gettext("%s is not an editable page"), $page));
+ }
+ if (! $form->submitted) {
+ $form->field(name => "rcsinfo",
+ value => rcs_prepedit($file), force => 1);
+ }
+ $form->field(name => "editcontent", validate => '/.*/');
+ }
+ else {
+ $type=$form->param('type');
+ if (defined $type && length $type && $hooks{htmlize}{$type}) {
+ $type=possibly_foolish_untaint($type);
+ }
+ elsif (defined $from && exists $pagesources{$from}) {
+ # favor the type of linking page
+ $type=pagetype($pagesources{$from});
+ }
+ $type=$config{default_pageext} unless defined $type;
+ $file=newpagefile($page, $type);
+ if (! $form->submitted) {
+ $form->field(name => "rcsinfo", value => "", force => 1);
+ }
+ $form->field(name => "editcontent", validate => '/.+/');
+ }
+
+ $form->field(name => "do", type => 'hidden');
+ $form->field(name => "sid", type => "hidden", value => $session->id,
+ force => 1);
+ $form->field(name => "from", type => 'hidden');
+ $form->field(name => "rcsinfo", type => 'hidden');
+ $form->field(name => "subpage", type => 'hidden');
+ $form->field(name => "page", value => $page, force => 1);
+ $form->field(name => "type", value => $type, force => 1);
+ $form->field(name => "comments", type => "text", size => 80);
+ $form->field(name => "editcontent", type => "textarea", rows => 20,
+ cols => 80);
+ $form->tmpl_param("can_commit", $config{rcs});
+ $form->tmpl_param("indexlink", indexlink());
+ $form->tmpl_param("helponformattinglink",
+ htmllink($page, $page, "ikiwiki/formatting",
+ noimageinline => 1,
+ linktext => "FormattingHelp"));
+
+ if ($form->submitted eq "Cancel") {
+ if ($form->field("do") eq "create" && defined $from) {
+ redirect($q, urlto($from, undef, 1));
+ }
+ elsif ($form->field("do") eq "create") {
+ redirect($q, $config{url});
+ }
+ else {
+ redirect($q, urlto($page, undef, 1));
+ }
+ exit;
+ }
+ elsif ($form->submitted eq "Preview") {
+ my $new=not exists $pagesources{$page};
+ if ($new) {
+ # temporarily record its type
+ $pagesources{$page}=$page.".".$type;
+ }
+ my %wasrendered=map { $_ => 1 } @{$renderedfiles{$page}};
+
+ my $content=$form->field('editcontent');
+
+ run_hooks(editcontent => sub {
+ $content=shift->(
+ content => $content,
+ page => $page,
+ cgi => $q,
+ session => $session,
+ );
+ });
+ my $preview=htmlize($page, $page, $type,
+ linkify($page, $page,
+ preprocess($page, $page,
+ filter($page, $page, $content), 0, 1)));
+ run_hooks(format => sub {
+ $preview=shift->(
+ page => $page,
+ content => $preview,
+ );
+ });
+ $form->tmpl_param("page_preview", $preview);
+
+ if ($new) {
+ delete $pagesources{$page};
+ }
+
+ # Previewing may have created files on disk.
+ # Keep a list of these to be deleted later.
+ my %previews = map { $_ => 1 } @{$wikistate{editpage}{previews}};
+ foreach my $f (@{$renderedfiles{$page}}) {
+ $previews{$f}=1 unless $wasrendered{$f};
+ }
+ @{$wikistate{editpage}{previews}} = keys %previews;
+ $renderedfiles{$page}=[keys %wasrendered];
+ saveindex();
+ }
+ elsif ($form->submitted eq "Save Page") {
+ $form->tmpl_param("page_preview", "");
+ }
+
+ if ($form->submitted ne "Save Page" || ! $form->validate) {
+ if ($form->field("do") eq "create") {
+ my @page_locs;
+ my $best_loc;
+ if (! defined $from || ! length $from ||
+ $from ne $form->field('from') ||
+ file_pruned($from, $config{srcdir}) ||
+ $from=~/^\// ||
+ $absolute ||
+ $form->submitted) {
+ @page_locs=$best_loc=$page;
+ }
+ else {
+ my $dir=$from."/";
+ $dir=~s![^/]+/+$!!;
+
+ if ((defined $form->field('subpage') &&
+ length $form->field('subpage')) ||
+ $page eq lc($config{discussionpage})) {
+ $best_loc="$from/$page";
+ }
+ else {
+ $best_loc=$dir.$page;
+ }
+
+ push @page_locs, $dir.$page;
+ push @page_locs, "$from/$page";
+ while (length $dir) {
+ $dir=~s![^/]+/+$!!;
+ push @page_locs, $dir.$page;
+ }
+
+ push @page_locs, "$config{userdir}/$page"
+ if length $config{userdir};
+ }
+
+ @page_locs = grep {
+ ! exists $pagecase{lc $_}
+ } @page_locs;
+ if (! @page_locs) {
+ # hmm, someone else made the page in the
+ # meantime?
+ if ($form->submitted eq "Preview") {
+ # let them go ahead with the edit
+ # and resolve the conflict at save
+ # time
+ @page_locs=$page;
+ }
+ else {
+ redirect($q, urlto($page, undef, 1));
+ exit;
+ }
+ }
+
+ my @editable_locs = grep {
+ check_canedit($_, $q, $session, 1)
+ } @page_locs;
+ if (! @editable_locs) {
+ # let it throw an error this time
+ map { check_canedit($_, $q, $session) } @page_locs;
+ }
+
+ my @page_types;
+ if (exists $hooks{htmlize}) {
+ foreach my $key (grep { !/^_/ } keys %{$hooks{htmlize}}) {
+ push @page_types, [$key, $hooks{htmlize}{$key}{longname} || $key];
+ }
+ }
+ @page_types=sort @page_types;
+
+ $form->tmpl_param("page_select", 1);
+ $form->field(name => "page", type => 'select',
+ options => [ map { [ $_, pagetitle($_, 1) ] } @editable_locs ],
+ value => $best_loc);
+ $form->field(name => "type", type => 'select',
+ options => \@page_types);
+ $form->title(sprintf(gettext("creating %s"), pagetitle($page)));
+
+ }
+ elsif ($form->field("do") eq "edit") {
+ check_canedit($page, $q, $session);
+ if (! defined $form->field('editcontent') ||
+ ! length $form->field('editcontent')) {
+ my $content="";
+ if (exists $pagesources{$page}) {
+ $content=readfile(srcfile($pagesources{$page}));
+ $content=~s/\n/\r\n/g;
+ }
+ $form->field(name => "editcontent", value => $content,
+ force => 1);
+ }
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->field(name => "type", type => 'hidden');
+ $form->title(sprintf(gettext("editing %s"), pagetitle($page)));
+ }
+
+ showform($form, \@buttons, $session, $q, forcebaseurl => $baseurl);
+ }
+ else {
+ # save page
+ check_canedit($page, $q, $session);
+ checksessionexpiry($q, $session, $q->param('sid'));
+
+ my $exists=-e "$config{srcdir}/$file";
+
+ if ($form->field("do") ne "create" && ! $exists &&
+ ! defined srcfile($file, 1)) {
+ $form->tmpl_param("message", template("editpagegone.tmpl")->output);
+ $form->field(name => "do", value => "create", force => 1);
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->field(name => "type", type => 'hidden');
+ $form->title(sprintf(gettext("editing %s"), $page));
+ showform($form, \@buttons, $session, $q, forcebaseurl => $baseurl);
+ exit;
+ }
+ elsif ($form->field("do") eq "create" && $exists) {
+ $form->tmpl_param("message", template("editcreationconflict.tmpl")->output);
+ $form->field(name => "do", value => "edit", force => 1);
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->field(name => "type", type => 'hidden');
+ $form->title(sprintf(gettext("editing %s"), $page));
+ $form->field("editcontent",
+ value => readfile("$config{srcdir}/$file").
+ "\n\n\n".$form->field("editcontent"),
+ force => 1);
+ showform($form, \@buttons, $session, $q, forcebaseurl => $baseurl);
+ exit;
+ }
+
+ my $message="";
+ if (defined $form->field('comments') &&
+ length $form->field('comments')) {
+ $message=$form->field('comments');
+ }
+
+ my $content=$form->field('editcontent');
+ check_content(content => $content, page => $page,
+ cgi => $q, session => $session,
+ subject => $message);
+ run_hooks(editcontent => sub {
+ $content=shift->(
+ content => $content,
+ page => $page,
+ cgi => $q,
+ session => $session,
+ );
+ });
+ $content=~s/\r\n/\n/g;
+ $content=~s/\r/\n/g;
+ $content.="\n" if $content !~ /\n$/;
+
+ $config{cgi}=0; # avoid cgi error message
+ eval { writefile($file, $config{srcdir}, $content) };
+ $config{cgi}=1;
+ if ($@) {
+ $form->field(name => "rcsinfo", value => rcs_prepedit($file),
+ force => 1);
+ my $mtemplate=template("editfailedsave.tmpl");
+ $mtemplate->param(error_message => $@);
+ $form->tmpl_param("message", $mtemplate->output);
+ $form->field("editcontent", value => $content, force => 1);
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->field(name => "type", type => 'hidden');
+ $form->title(sprintf(gettext("editing %s"), $page));
+ showform($form, \@buttons, $session, $q,
+ forcebaseurl => $baseurl);
+ exit;
+ }
+
+ my $conflict;
+ if ($config{rcs}) {
+ if (! $exists) {
+ rcs_add($file);
+ }
+
+ # Prevent deadlock with post-commit hook by
+ # signaling to it that it should not try to
+ # do anything.
+ disable_commit_hook();
+ $conflict=rcs_commit($file, $message,
+ $form->field("rcsinfo"),
+ $session->param("name"), $ENV{REMOTE_ADDR});
+ enable_commit_hook();
+ rcs_update();
+ }
+
+ # Refresh even if there was a conflict, since other changes
+ # may have been committed while the post-commit hook was
+ # disabled.
+ require IkiWiki::Render;
+ refresh();
+ saveindex();
+
+ if (defined $conflict) {
+ $form->field(name => "rcsinfo", value => rcs_prepedit($file),
+ force => 1);
+ $form->tmpl_param("message", template("editconflict.tmpl")->output);
+ $form->field("editcontent", value => $conflict, force => 1);
+ $form->field("do", "edit", force => 1);
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->field(name => "type", type => 'hidden');
+ $form->title(sprintf(gettext("editing %s"), $page));
+ showform($form, \@buttons, $session, $q,
+ forcebaseurl => $baseurl);
+ }
+ else {
+ # The trailing question mark tries to avoid broken
+ # caches and get the most recent version of the page.
+ redirect($q, urlto($page, undef, 1)."?updated");
+ }
+ }
+
+ exit;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use HTML::Template;
use Encode;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "edittemplate",
+ call => \&getsetup);
hook(type => "needsbuild", id => "edittemplate",
call => \&needsbuild);
hook(type => "preprocess", id => "edittemplate",
call => \&preprocess);
hook(type => "formbuilder", id => "edittemplate",
call => \&formbuilder);
-} #}}}
+}
-sub needsbuild (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub needsbuild (@) {
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
}
}
}
-} #}}}
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
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};
+ my $link=linkpage($params{template});
+ $pagestate{$params{page}}{edittemplate}{$params{match}}=$link;
+ return "" if ($params{silent} && IkiWiki::yesno($params{silent}));
+ add_depends($params{page}, $link);
return sprintf(gettext("edittemplate %s registered for %s"),
- $params{template}, $params{match});
-} # }}}
+ htmllink($params{page}, $params{destpage}, $link),
+ $params{match});
+}
-sub formbuilder (@) { #{{{
+sub formbuilder (@) {
my %params=@_;
my $form=$params{form};
- return if $form->field("do") ne "create";
+ return if $form->field("do") ne "create" ||
+ (defined $form->field("editcontent") && length $form->field("editcontent"));
+
my $page=$form->field("page");
# The tricky bit here is that $page is probably just the base
if (exists $pagestate{$registering_page}{edittemplate}) {
foreach my $pagespec (sort keys %{$pagestate{$registering_page}{edittemplate}}) {
if (pagespec_match($p, $pagespec, location => $registering_page)) {
+ my $template=$pagestate{$registering_page}{edittemplate}{$pagespec};
$form->field(name => "editcontent",
- value => filltemplate($pagestate{$registering_page}{edittemplate}{$pagespec}, $page));
+ value => filltemplate($template, $page));
+ $form->field(name => "type",
+ value => pagetype($pagesources{$template}))
+ if $pagesources{$template};
return;
}
}
}
}
}
-} #}}}
+}
-sub filltemplate ($$) { #{{{
+sub filltemplate ($$) {
my $template_page=shift;
my $page=shift;
);
};
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);
return $template->output;
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my $attribr=qr/[^<>"]+/;
my @embedded;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "embed", call => \&getsetup);
hook(type => "filter", id => "embed", call => \&filter);
-} # }}}
+}
-sub embed ($) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub embed ($) {
hook(type => "format", id => "embed", call => \&format) unless @embedded;
push @embedded, shift;
return "<div class=\"embed$#embedded\"></div>";
-} #}}}
+}
-sub filter (@) { #{{{
+sub filter (@) {
my %params=@_;
$params{content} =~ s/$safehtml/embed($1)/eg;
return $params{content};
-} # }}}
+}
-sub format (@) { #{{{
+sub format (@) {
my %params=@_;
$params{content} =~ s/<div class="embed(\d+)"><\/div>/$embedded[$1]/eg;
return $params{content};
-} # }}}
+}
1
#!/usr/bin/perl
# Support for external plugins written in other languages.
-# Communication via XML RPC a pipe.
+# Communication via XML RPC to a pipe.
# See externaldemo for an example of a plugin that uses this.
package IkiWiki::Plugin::external;
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use RPC::XML;
use RPC::XML::Parser;
use IPC::Open2;
my %plugins;
-sub import { #{{{
+sub import {
my $self=shift;
my $plugin=shift;
return unless defined $plugin;
$RPC::XML::ENCODING="utf-8";
rpc_call($plugins{$plugin}, "import");
-} #}}}
+}
-sub rpc_write ($$) { #{{{
+sub rpc_write ($$) {
my $fh=shift;
my $string=shift;
$fh->print($string."\n");
$fh->flush;
-} #}}}
+}
-sub rpc_call ($$;@) { #{{{
+sub rpc_call ($$;@) {
my $plugin=shift;
my $command=shift;
}
return undef;
-} #}}}
+}
package IkiWiki::RPC::XML;
use Memoize;
-sub getvar ($$$) { #{{{
+sub getvar ($$$) {
my $plugin=shift;
my $varname="IkiWiki::".shift;
my $key=shift;
my $ret=$varname->{$key};
use strict 'refs';
return $ret;
-} #}}}
+}
-sub setvar ($$$;@) { #{{{
+sub setvar ($$$;@) {
my $plugin=shift;
my $varname="IkiWiki::".shift;
my $key=shift;
my $ret=$varname->{$key}=$value;
use strict 'refs';
return $ret;
-} #}}}
+}
-sub getstate ($$$$) { #{{{
+sub getstate ($$$$) {
my $plugin=shift;
my $page=shift;
my $id=shift;
my $key=shift;
return $IkiWiki::pagestate{$page}{$id}{$key};
-} #}}}
+}
-sub setstate ($$$$;@) { #{{{
+sub setstate ($$$$;@) {
my $plugin=shift;
my $page=shift;
my $id=shift;
my $value=shift;
return $IkiWiki::pagestate{$page}{$id}{$key}=$value;
-} #}}}
+}
-sub getargv ($) { #{{{
+sub getargv ($) {
my $plugin=shift;
return \@ARGV;
-} #}}}
+}
-sub setargv ($@) { #{{{
+sub setargv ($@) {
my $plugin=shift;
my $array=shift;
@ARGV=@$array;
-} #}}}
+}
-sub inject ($@) { #{{{
+sub inject ($@) {
# Bind a given perl function name to a particular RPC request.
my $plugin=shift;
my %params=@_;
my $sub = sub {
IkiWiki::Plugin::external::rpc_call($plugin, $params{call}, @_)
};
+ $sub=memoize($sub) if $params{memoize};
+
+ # This will add it to the symbol table even if not present.
+ no warnings;
eval qq{*$params{name}=\$sub};
- memoize($params{name}) if $params{memoize};
+ use warnings;
+
+ # This will ensure that everywhere it was exported to sees
+ # the injected version.
+ IkiWiki::inject(name => $params{name}, call => $sub);
return 1;
-} #}}}
+}
-sub hook ($@) { #{{{
+sub hook ($@) {
# the call parameter is a function name to call, since XML RPC
# cannot pass a function reference
my $plugin=shift;
delete $params{call};
IkiWiki::hook(%params, call => sub {
- my $ret=IkiWiki::Plugin::external::rpc_call($plugin, $callback, @_);
- return $ret;
+ IkiWiki::Plugin::external::rpc_call($plugin, $callback, @_);
});
-} #}}}
+}
-sub pagespec_match ($@) { #{{{
- # convert pagespec_match's return object into a XML RPC boolean
+sub pagespec_match ($@) {
+ # convert return object into a XML RPC boolean
my $plugin=shift;
+ my $page=shift;
+ my $spec=shift;
- return RPC::XML::boolean->new(0 + IkiWiki::pagespec_march(@_));
-} #}}}
+ return RPC::XML::boolean->new(0 + IkiWiki::pagespec_match(
+ $page, $spec, @_));
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "favicon", call => \&getsetup);
hook(type => "pagetemplate", id => "favicon", call => \&pagetemplate);
-} # }}}
+}
-sub pagetemplate (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub pagetemplate (@) {
my %params=@_;
my $template=$params{template};
if ($template->query(name => "favicon")) {
$template->param(favicon => "favicon.ico");
}
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::filecheck;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+my %units=( #{{{ # size in bytes
+ B => 1,
+ byte => 1,
+ KB => 2 ** 10,
+ kilobyte => 2 ** 10,
+ K => 2 ** 10,
+ KB => 2 ** 10,
+ kilobyte => 2 ** 10,
+ M => 2 ** 20,
+ MB => 2 ** 20,
+ megabyte => 2 ** 20,
+ G => 2 ** 30,
+ GB => 2 ** 30,
+ gigabyte => 2 ** 30,
+ T => 2 ** 40,
+ TB => 2 ** 40,
+ terabyte => 2 ** 40,
+ P => 2 ** 50,
+ PB => 2 ** 50,
+ petabyte => 2 ** 50,
+ E => 2 ** 60,
+ EB => 2 ** 60,
+ exabyte => 2 ** 60,
+ Z => 2 ** 70,
+ ZB => 2 ** 70,
+ zettabyte => 2 ** 70,
+ Y => 2 ** 80,
+ YB => 2 ** 80,
+ yottabyte => 2 ** 80,
+ # ikiwiki, if you find you need larger data quantities, either modify
+ # yourself to add them, or travel back in time to 2008 and kill me.
+ # -- Joey
+);
+
+sub parsesize ($) {
+ my $size=shift;
+
+ no warnings;
+ my $base=$size+0; # force to number
+ use warnings;
+ foreach my $unit (sort keys %units) {
+ if ($size=~/[0-9\s]\Q$unit\E$/i) {
+ return $base * $units{$unit};
+ }
+ }
+ return $base;
+}
+
+# This is provided for other plugins that want to convert back the other way.
+sub humansize ($) {
+ my $size=shift;
+
+ foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
+ if ($size / $units{$unit} > 0.25) {
+ return (int($size / $units{$unit} * 10)/10).$unit;
+ }
+ }
+ return $size; # near zero, or negative
+}
+
+package IkiWiki::PageSpec;
+
+sub match_maxsize ($$;@) {
+ my $page=shift;
+ my $maxsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)};
+ if ($@) {
+ return IkiWiki::ErrorReason->new("unable to parse maxsize (or number too large)");
+ }
+
+ my %params=@_;
+ my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+ if (! defined $file) {
+ return IkiWiki::ErrorReason->new("no file specified");
+ }
+
+ if (-s $file > $maxsize) {
+ return IkiWiki::FailReason->new("file too large (".(-s $file)." > $maxsize)");
+ }
+ else {
+ return IkiWiki::SuccessReason->new("file not too large");
+ }
+}
+
+sub match_minsize ($$;@) {
+ my $page=shift;
+ my $minsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)};
+ if ($@) {
+ return IkiWiki::ErrorReason->new("unable to parse minsize (or number too large)");
+ }
+
+ my %params=@_;
+ my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+ if (! defined $file) {
+ return IkiWiki::ErrorReason->new("no file specified");
+ }
+
+ if (-s $file < $minsize) {
+ return IkiWiki::FailReason->new("file too small");
+ }
+ else {
+ return IkiWiki::SuccessReason->new("file not too small");
+ }
+}
+
+sub match_mimetype ($$;@) {
+ my $page=shift;
+ my $wanted=shift;
+
+ my %params=@_;
+ my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+ if (! defined $file) {
+ return IkiWiki::ErrorReason->new("no file specified");
+ }
+
+ # Use ::magic to get the mime type, the idea is to only trust
+ # data obtained by examining the actual file contents.
+ eval q{use File::MimeInfo::Magic};
+ if ($@) {
+ return IkiWiki::ErrorReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
+ }
+ my $mimetype=File::MimeInfo::Magic::magic($file);
+ if (! defined $mimetype) {
+ $mimetype=File::MimeInfo::Magic::default($file);
+ if (! defined $mimetype) {
+ $mimetype="unknown";
+ }
+ }
+
+ my $regexp=IkiWiki::glob2re($wanted);
+ if ($mimetype!~/^$regexp$/i) {
+ return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
+ }
+ else {
+ return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
+ }
+}
+
+sub match_virusfree ($$;@) {
+ my $page=shift;
+ my $wanted=shift;
+
+ my %params=@_;
+ my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+ if (! defined $file) {
+ return IkiWiki::ErrorReason->new("no file specified");
+ }
+
+ if (! exists $IkiWiki::config{virus_checker} ||
+ ! length $IkiWiki::config{virus_checker}) {
+ return IkiWiki::ErrorReason->new("no virus_checker configured");
+ }
+
+ # The file needs to be fed into the virus checker on stdin,
+ # because the file is not world-readable, and if clamdscan is
+ # used, clamd would fail to read it.
+ eval q{use IPC::Open2};
+ error($@) if $@;
+ open (IN, "<", $file) || return IkiWiki::ErrorReason->new("failed to read file");
+ binmode(IN);
+ my $sigpipe=0;
+ $SIG{PIPE} = sub { $sigpipe=1 };
+ my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker});
+ my $reason=<CHECKER_OUT>;
+ chomp $reason;
+ 1 while (<CHECKER_OUT>);
+ close(CHECKER_OUT);
+ waitpid $pid, 0;
+ $SIG{PIPE}="DEFAULT";
+ if ($sigpipe || $?) {
+ if (! length $reason) {
+ $reason="virus checker $IkiWiki::config{virus_checker}; failed with no output";
+ }
+ return IkiWiki::FailReason->new("file seems to contain a virus ($reason)");
+ }
+ else {
+ return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
+ }
+}
+
+sub match_ispage ($$;@) {
+ my $filename=shift;
+
+ if (defined IkiWiki::pagetype($filename)) {
+ return IkiWiki::SuccessReason->new("file is a wiki page");
+ }
+ else {
+ return IkiWiki::FailReason->new("file is not a wiki page");
+ }
+}
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::format;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "preprocess", id => "format", call => \&preprocess);
+}
+
+sub preprocess (@) {
+ my %params=@_;
+ my $format=shift;
+ shift;
+ my $text=IkiWiki::preprocess($params{page}, $params{destpage}, shift);
+ shift;
+
+ if (! defined $format || ! defined $text) {
+ error(gettext("must specify format and text"));
+ }
+ elsif (exists $IkiWiki::hooks{htmlize}{$format}) {
+ return IkiWiki::htmlize($params{page}, $params{destpage},
+ $format, $text);
+ }
+ else {
+ # Other plugins can register htmlizefallback
+ # hooks to add support for page types
+ # not suitable for htmlize. Try them until
+ # one succeeds.
+ my $ret;
+ IkiWiki::run_hooks(htmlizefallback => sub {
+ $ret=shift->($format, $text)
+ unless defined $ret;
+ });
+ return $ret if defined $ret;
+
+ error(sprintf(gettext("unsupported page format %s"), $format));
+ }
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "fortune", call => \&getsetup);
hook(type => "preprocess", id => "fortune", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
$ENV{PATH}="$ENV{PATH}:/usr/games:/usr/local/games";
my $f = `fortune 2>/dev/null`;
if ($?) {
- return "[[".gettext("fortune failed")."]]";
+ error gettext("fortune failed");
}
else {
return "<pre>$f</pre>\n";
}
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::getsource;
+
+use warnings;
+use strict;
+use IkiWiki;
+use open qw{:utf8 :std};
+
+sub import {
+ hook(type => "getsetup", id => "getsource", call => \&getsetup);
+ hook(type => "pagetemplate", id => "getsource", call => \&pagetemplate);
+ hook(type => "cgi", id => "getsource", call => \&cgi_getsource);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ getsource_mimetype => {
+ type => "string",
+ example => "text/plain; charset=utf-8",
+ description => "Mime type for returned source.",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub pagetemplate (@) {
+ my %params=@_;
+
+ my $page=$params{page};
+ my $template=$params{template};
+
+ if (length $config{cgiurl}) {
+ $template->param(getsourceurl => IkiWiki::cgiurl(do => "getsource", page => $page));
+ $template->param(have_actions => 1);
+ }
+}
+
+sub cgi_getsource ($) {
+ my $cgi=shift;
+
+ return unless defined $cgi->param('do') &&
+ $cgi->param("do") eq "getsource";
+
+ IkiWiki::decode_cgi_utf8($cgi);
+
+ my $page=$cgi->param('page');
+
+ if (! defined $page || $page !~ /$config{wiki_file_regexp}/) {
+ error("invalid page parameter");
+ }
+
+ # For %pagesources.
+ IkiWiki::loadindex();
+
+ if (! exists $pagesources{$page}) {
+ IkiWiki::cgi_custom_failure(
+ $cgi->header(-status => "404 Not Found"),
+ IkiWiki::misctemplate(gettext("missing page"),
+ "<p>".
+ sprintf(gettext("The page %s does not exist."),
+ htmllink("", "", $page)).
+ "</p>"));
+ exit;
+ }
+
+ if (! defined pagetype($pagesources{$page})) {
+ IkiWiki::cgi_custom_failure(
+ $cgi->header(-status => "403 Forbidden"),
+ IkiWiki::misctemplate(gettext("not a page"),
+ "<p>".
+ sprintf(gettext("%s is an attachment, not a page."),
+ htmllink("", "", $page)).
+ "</p>"));
+ exit;
+ }
+
+ if (! $config{getsource_mimetype}) {
+ $config{getsource_mimetype} = "text/plain; charset=utf-8";
+ }
+
+ print "Content-Type: $config{getsource_mimetype}\r\n";
+ print ("\r\n");
+ print readfile(srcfile($pagesources{$page}));
+
+ exit 0;
+}
+
+1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::git;
+
+use warnings;
+use strict;
+use IkiWiki;
+use Encode;
+use open qw{:utf8 :std};
+
+my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums
+my $dummy_commit_msg = 'dummy commit'; # message to skip in recent changes
+my $no_chdir=0;
+
+sub import {
+ hook(type => "checkconfig", id => "git", call => \&checkconfig);
+ hook(type => "getsetup", id => "git", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+ hook(type => "rcs", id => "rcs_receive", call => \&rcs_receive);
+}
+
+sub checkconfig () {
+ if (! defined $config{gitorigin_branch}) {
+ $config{gitorigin_branch}="origin";
+ }
+ if (! defined $config{gitmaster_branch}) {
+ $config{gitmaster_branch}="master";
+ }
+ if (defined $config{git_wrapper} &&
+ length $config{git_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{git_wrapper},
+ wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"),
+ };
+ }
+ if (defined $config{git_test_receive_wrapper} &&
+ length $config{git_test_receive_wrapper}) {
+ push @{$config{wrappers}}, {
+ test_receive => 1,
+ wrapper => $config{git_test_receive_wrapper},
+ wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ git_wrapper => {
+ type => "string",
+ example => "/git/wiki.git/hooks/post-update",
+ description => "git hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ git_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for git_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ git_test_receive_wrapper => {
+ type => "string",
+ example => "/git/wiki.git/hooks/pre-receive",
+ description => "git pre-receive hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ untrusted_committers => {
+ type => "string",
+ example => [],
+ description => "unix users whose commits should be checked by the pre-receive hook",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=history;f=[[file]]",
+ description => "gitweb url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=blobdiff;f=[[file]];h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_commit]];hpb=[[sha1_parent]]",
+ description => "gitweb url to show a diff ([[file]], [[sha1_to]], [[sha1_from]], [[sha1_commit]], and [[sha1_parent]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ gitorigin_branch => {
+ type => "string",
+ example => "origin",
+ description => "where to pull and push changes (set to empty string to disable)",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ gitmaster_branch => {
+ type => "string",
+ example => "master",
+ description => "branch that the wiki is stored in",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+}
+
+sub safe_git (&@) {
+ # Start a child process safely without resorting /bin/sh.
+ # Return command output or success state (in scalar context).
+
+ my ($error_handler, @cmdline) = @_;
+
+ my $pid = open my $OUT, "-|";
+
+ error("Cannot fork: $!") if !defined $pid;
+
+ if (!$pid) {
+ # In child.
+ # Git commands want to be in wc.
+ if (! $no_chdir) {
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+ }
+ exec @cmdline or error("Cannot exec '@cmdline': $!");
+ }
+ # In parent.
+
+ # git output is probably utf-8 encoded, but may contain
+ # other encodings or invalidly encoded stuff. So do not rely
+ # on the normal utf-8 IO layer, decode it by hand.
+ binmode($OUT);
+
+ my @lines;
+ while (<$OUT>) {
+ $_=decode_utf8($_, 0);
+
+ chomp;
+
+ push @lines, $_;
+ }
+
+ close $OUT;
+
+ $error_handler->("'@cmdline' failed: $!") if $? && $error_handler;
+
+ return wantarray ? @lines : ($? == 0);
+}
+# Convenient wrappers.
+sub run_or_die ($@) { safe_git(\&error, @_) }
+sub run_or_cry ($@) { safe_git(sub { warn @_ }, @_) }
+sub run_or_non ($@) { safe_git(undef, @_) }
+
+
+sub merge_past ($$$) {
+ # Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'.
+ # Git merge commands work with the committed changes, except in the
+ # implicit case of '-m' of git checkout(1). So we should invent a
+ # kludge here. In principle, we need to create a throw-away branch
+ # in preparing for the merge itself. Since branches are cheap (and
+ # branching is fast), this shouldn't cost high.
+ #
+ # The main problem is the presence of _uncommitted_ local changes. One
+ # possible approach to get rid of this situation could be that we first
+ # make a temporary commit in the master branch and later restore the
+ # initial state (this is possible since Git has the ability to undo a
+ # commit, i.e. 'git reset --soft HEAD^'). The method can be summarized
+ # as follows:
+ #
+ # - create a diff of HEAD:current-sha1
+ # - dummy commit
+ # - create a dummy branch and switch to it
+ # - rewind to past (reset --hard to the current-sha1)
+ # - apply the diff and commit
+ # - switch to master and do the merge with the dummy branch
+ # - make a soft reset (undo the last commit of master)
+ #
+ # The above method has some drawbacks: (1) it needs a redundant commit
+ # just to get rid of local changes, (2) somewhat slow because of the
+ # required system forks. Until someone points a more straight method
+ # (which I would be grateful) I have implemented an alternative method.
+ # In this approach, we hide all the modified files from Git by renaming
+ # them (using the 'rename' builtin) and later restore those files in
+ # the throw-away branch (that is, we put the files themselves instead
+ # of applying a patch).
+
+ my ($sha1, $file, $message) = @_;
+
+ my @undo; # undo stack for cleanup in case of an error
+ my $conflict; # file content with conflict markers
+
+ eval {
+ # Hide local changes from Git by renaming the modified file.
+ # Relative paths must be converted to absolute for renaming.
+ my ($target, $hidden) = (
+ "$config{srcdir}/${file}", "$config{srcdir}/${file}.${sha1}"
+ );
+ rename($target, $hidden)
+ or error("rename '$target' to '$hidden' failed: $!");
+ # Ensure to restore the renamed file on error.
+ push @undo, sub {
+ return if ! -e "$hidden"; # already renamed
+ rename($hidden, $target)
+ or warn "rename '$hidden' to '$target' failed: $!";
+ };
+
+ my $branch = "throw_away_${sha1}"; # supposed to be unique
+
+ # Create a throw-away branch and rewind backward.
+ push @undo, sub { run_or_cry('git', 'branch', '-D', $branch) };
+ run_or_die('git', 'branch', $branch, $sha1);
+
+ # Switch to throw-away branch for the merge operation.
+ push @undo, sub {
+ if (!run_or_cry('git', 'checkout', $config{gitmaster_branch})) {
+ run_or_cry('git', 'checkout','-f',$config{gitmaster_branch});
+ }
+ };
+ run_or_die('git', 'checkout', $branch);
+
+ # Put the modified file in _this_ branch.
+ rename($hidden, $target)
+ or error("rename '$hidden' to '$target' failed: $!");
+
+ # _Silently_ commit all modifications in the current branch.
+ run_or_non('git', 'commit', '-m', $message, '-a');
+ # ... and re-switch to master.
+ run_or_die('git', 'checkout', $config{gitmaster_branch});
+
+ # Attempt to merge without complaining.
+ if (!run_or_non('git', 'pull', '--no-commit', '.', $branch)) {
+ $conflict = readfile($target);
+ run_or_die('git', 'reset', '--hard');
+ }
+ };
+ my $failure = $@;
+
+ # Process undo stack (in reverse order). By policy cleanup
+ # actions should normally print a warning on failure.
+ while (my $handle = pop @undo) {
+ $handle->();
+ }
+
+ error("Git merge failed!\n$failure\n") if $failure;
+
+ return $conflict;
+}
+
+sub parse_diff_tree ($@) {
+ # Parse the raw diff tree chunk and return the info hash.
+ # See git-diff-tree(1) for the syntax.
+
+ my ($prefix, $dt_ref) = @_;
+
+ # End of stream?
+ return if !defined @{ $dt_ref } ||
+ !defined @{ $dt_ref }[0] || !length @{ $dt_ref }[0];
+
+ my %ci;
+ # Header line.
+ while (my $line = shift @{ $dt_ref }) {
+ return if $line !~ m/^(.+) ($sha1_pattern)/;
+
+ my $sha1 = $2;
+ $ci{'sha1'} = $sha1;
+ last;
+ }
+
+ # Identification lines for the commit.
+ while (my $line = shift @{ $dt_ref }) {
+ # Regexps are semi-stolen from gitweb.cgi.
+ if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) {
+ $ci{'tree'} = $1;
+ }
+ elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) {
+ # XXX: collecting in reverse order
+ push @{ $ci{'parents'} }, $1;
+ }
+ elsif ($line =~ m/^(author|committer) (.*) ([0-9]+) (.*)$/) {
+ my ($who, $name, $epoch, $tz) =
+ ($1, $2, $3, $4 );
+
+ $ci{ $who } = $name;
+ $ci{ "${who}_epoch" } = $epoch;
+ $ci{ "${who}_tz" } = $tz;
+
+ if ($name =~ m/^[^<]+\s+<([^@>]+)/) {
+ $ci{"${who}_username"} = $1;
+ }
+ elsif ($name =~ m/^([^<]+)\s+<>$/) {
+ $ci{"${who}_username"} = $1;
+ }
+ else {
+ $ci{"${who}_username"} = $name;
+ }
+ }
+ elsif ($line =~ m/^$/) {
+ # Trailing empty line signals next section.
+ last;
+ }
+ }
+
+ debug("No 'tree' seen in diff-tree output") if !defined $ci{'tree'};
+
+ if (defined $ci{'parents'}) {
+ $ci{'parent'} = @{ $ci{'parents'} }[0];
+ }
+ else {
+ $ci{'parent'} = 0 x 40;
+ }
+
+ # Commit message (optional).
+ while ($dt_ref->[0] =~ /^ /) {
+ my $line = shift @{ $dt_ref };
+ $line =~ s/^ //;
+ push @{ $ci{'comment'} }, $line;
+ }
+ shift @{ $dt_ref } if $dt_ref->[0] =~ /^$/;
+
+ # Modified files.
+ while (my $line = shift @{ $dt_ref }) {
+ if ($line =~ m{^
+ (:+) # number of parents
+ ([^\t]+)\t # modes, sha1, status
+ (.*) # file names
+ $}xo) {
+ my $num_parents = length $1;
+ my @tmp = split(" ", $2);
+ my ($file, $file_to) = split("\t", $3);
+ my @mode_from = splice(@tmp, 0, $num_parents);
+ my $mode_to = shift(@tmp);
+ my @sha1_from = splice(@tmp, 0, $num_parents);
+ my $sha1_to = shift(@tmp);
+ my $status = shift(@tmp);
+
+ # git does not output utf-8 filenames, but instead
+ # double-quotes them with the utf-8 characters
+ # escaped as \nnn\nnn.
+ if ($file =~ m/^"(.*)"$/) {
+ ($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg;
+ }
+ $file =~ s/^\Q$prefix\E//;
+ if (length $file) {
+ push @{ $ci{'details'} }, {
+ 'file' => decode("utf8", $file),
+ 'sha1_from' => $sha1_from[0],
+ 'sha1_to' => $sha1_to,
+ 'mode_from' => $mode_from[0],
+ 'mode_to' => $mode_to,
+ 'status' => $status,
+ };
+ }
+ next;
+ };
+ last;
+ }
+
+ return \%ci;
+}
+
+sub git_commit_info ($;$) {
+ # Return an array of commit info hashes of num commits
+ # starting from the given sha1sum.
+ my ($sha1, $num) = @_;
+
+ my @opts;
+ push @opts, "--max-count=$num" if defined $num;
+
+ my @raw_lines = run_or_die('git', 'log', @opts,
+ '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c',
+ '-r', $sha1, '--', '.');
+ my ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix');
+
+ my @ci;
+ while (my $parsed = parse_diff_tree(($prefix or ""), \@raw_lines)) {
+ push @ci, $parsed;
+ }
+
+ warn "Cannot parse commit info for '$sha1' commit" if !@ci;
+
+ return wantarray ? @ci : $ci[0];
+}
+
+sub git_sha1 (;$) {
+ # Return head sha1sum (of given file).
+ my $file = shift || q{--};
+
+ # Ignore error since a non-existing file might be given.
+ my ($sha1) = run_or_non('git', 'rev-list', '--max-count=1', 'HEAD',
+ '--', $file);
+ if ($sha1) {
+ ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now
+ } else { debug("Empty sha1sum for '$file'.") }
+ return defined $sha1 ? $sha1 : q{};
+}
+
+sub rcs_update () {
+ # Update working directory.
+
+ if (length $config{gitorigin_branch}) {
+ run_or_cry('git', 'pull', $config{gitorigin_branch});
+ }
+}
+
+sub rcs_prepedit ($) {
+ # Return the commit sha1sum of the file when editing begins.
+ # This will be later used in rcs_commit if a merge is required.
+ my ($file) = @_;
+
+ return git_sha1($file);
+}
+
+sub rcs_commit ($$$;$$) {
+ # Try to commit the page; returns undef on _success_ and
+ # a version of the page with the rcs's conflict markers on
+ # failure.
+
+ my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+
+ # Check to see if the page has been changed by someone else since
+ # rcs_prepedit was called.
+ my $cur = git_sha1($file);
+ my ($prev) = $rcstoken =~ /^($sha1_pattern)$/; # untaint
+
+ if (defined $cur && defined $prev && $cur ne $prev) {
+ my $conflict = merge_past($prev, $file, $dummy_commit_msg);
+ return $conflict if defined $conflict;
+ }
+
+ rcs_add($file);
+ return rcs_commit_staged($message, $user, $ipaddr);
+}
+
+sub rcs_commit_staged ($$$) {
+ # Commits all staged changes. Changes can be staged using rcs_add,
+ # rcs_remove, and rcs_rename.
+ my ($message, $user, $ipaddr)=@_;
+
+ # Set the commit author and email to the web committer.
+ my %env=%ENV;
+ if (defined $user || defined $ipaddr) {
+ my $u=encode_utf8(defined $user ? $user : $ipaddr);
+ $ENV{GIT_AUTHOR_NAME}=$u;
+ $ENV{GIT_AUTHOR_EMAIL}="$u\@web";
+ }
+
+ $message = IkiWiki::possibly_foolish_untaint($message);
+ my @opts;
+ if ($message !~ /\S/) {
+ # Force git to allow empty commit messages.
+ # (If this version of git supports it.)
+ my ($version)=`git --version` =~ /git version (.*)/;
+ if ($version ge "1.5.4") {
+ push @opts, '--cleanup=verbatim';
+ }
+ else {
+ $message.=".";
+ }
+ }
+ push @opts, '-q';
+ # git commit returns non-zero if file has not been really changed.
+ # so we should ignore its exit status (hence run_or_non).
+ if (run_or_non('git', 'commit', @opts, '-m', $message)) {
+ if (length $config{gitorigin_branch}) {
+ run_or_cry('git', 'push', $config{gitorigin_branch});
+ }
+ }
+
+ %ENV=%env;
+ return undef; # success
+}
+
+sub rcs_add ($) {
+ # Add file to archive.
+
+ my ($file) = @_;
+
+ run_or_cry('git', 'add', $file);
+}
+
+sub rcs_remove ($) {
+ # Remove file from archive.
+
+ my ($file) = @_;
+
+ run_or_cry('git', 'rm', '-f', $file);
+}
+
+sub rcs_rename ($$) {
+ my ($src, $dest) = @_;
+
+ run_or_cry('git', 'mv', '-f', $src, $dest);
+}
+
+sub rcs_recentchanges ($) {
+ # List of recent changes.
+
+ my ($num) = @_;
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+
+ my @rets;
+ foreach my $ci (git_commit_info('HEAD', $num || 1)) {
+ # Skip redundant commits.
+ next if ($ci->{'comment'} && @{$ci->{'comment'}}[0] eq $dummy_commit_msg);
+
+ my ($sha1, $when) = (
+ $ci->{'sha1'},
+ $ci->{'author_epoch'}
+ );
+
+ my @pages;
+ foreach my $detail (@{ $ci->{'details'} }) {
+ my $file = $detail->{'file'};
+
+ my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : "";
+ $diffurl =~ s/\[\[file\]\]/$file/go;
+ $diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go;
+ $diffurl =~ s/\[\[sha1_from\]\]/$detail->{'sha1_from'}/go;
+ $diffurl =~ s/\[\[sha1_to\]\]/$detail->{'sha1_to'}/go;
+ $diffurl =~ s/\[\[sha1_commit\]\]/$sha1/go;
+
+ push @pages, {
+ page => pagename($file),
+ diffurl => $diffurl,
+ };
+ }
+
+ my @messages;
+ my $pastblank=0;
+ foreach my $line (@{$ci->{'comment'}}) {
+ $pastblank=1 if $line eq '';
+ next if $pastblank && $line=~m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i;
+ push @messages, { line => $line };
+ }
+
+ my $user=$ci->{'author_username'};
+ my $web_commit = ($ci->{'author'} =~ /\@web>/);
+
+ # compatability code for old web commit messages
+ if (! $web_commit &&
+ defined $messages[0] &&
+ $messages[0]->{line} =~ m/$config{web_commit_regexp}/) {
+ $user = defined $2 ? "$2" : "$3";
+ $messages[0]->{line} = $4;
+ $web_commit=1;
+ }
+
+ push @rets, {
+ rev => $sha1,
+ user => $user,
+ committype => $web_commit ? "web" : "git",
+ when => $when,
+ message => [@messages],
+ pages => [@pages],
+ } if @pages;
+
+ last if @rets >= $num;
+ }
+
+ return @rets;
+}
+
+sub rcs_diff ($) {
+ my $rev=shift;
+ my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint
+ my @lines;
+ foreach my $line (run_or_non("git", "show", $sha1)) {
+ if (@lines || $line=~/^diff --git/) {
+ push @lines, $line."\n";
+ }
+ }
+ if (wantarray) {
+ return @lines;
+ }
+ else {
+ return join("", @lines);
+ }
+}
+
+sub rcs_getctime ($) {
+ my $file=shift;
+ # Remove srcdir prefix
+ $file =~ s/^\Q$config{srcdir}\E\/?//;
+
+ my @sha1s = run_or_non('git', 'rev-list', 'HEAD', '--', $file);
+ my $ci = git_commit_info($sha1s[$#sha1s], 1);
+ my $ctime = $ci->{'author_epoch'};
+ debug("ctime for '$file': ". localtime($ctime));
+
+ return $ctime;
+}
+
+sub rcs_receive () {
+ # The wiki may not be the only thing in the git repo.
+ # Determine if it is in a subdirectory by examining the srcdir,
+ # and its parents, looking for the .git directory.
+ my $subdir="";
+ my $dir=$config{srcdir};
+ while (! -d "$dir/.git") {
+ $subdir=IkiWiki::basename($dir)."/".$subdir;
+ $dir=IkiWiki::dirname($dir);
+ if (! length $dir) {
+ error("cannot determine root of git repo");
+ }
+ }
+
+ my @rets;
+ while (<>) {
+ chomp;
+ my ($oldrev, $newrev, $refname) = split(' ', $_, 3);
+
+ # only allow changes to gitmaster_branch
+ if ($refname !~ /^refs\/heads\/\Q$config{gitmaster_branch}\E$/) {
+ error sprintf(gettext("you are not allowed to change %s"), $refname);
+ }
+
+ # Avoid chdir when running git here, because the changes
+ # are in the master git repo, not the srcdir repo.
+ # The pre-recieve hook already puts us in the right place.
+ $no_chdir=1;
+ my @changes=git_commit_info($oldrev."..".$newrev);
+ $no_chdir=0;
+
+ foreach my $ci (@changes) {
+ foreach my $detail (@{ $ci->{'details'} }) {
+ my $file = $detail->{'file'};
+
+ # check that all changed files are in the
+ # subdir
+ if (length $subdir &&
+ ! ($file =~ s/^\Q$subdir\E//)) {
+ error sprintf(gettext("you are not allowed to change %s"), $file);
+ }
+
+ my ($action, $mode, $path);
+ if ($detail->{'status'} =~ /^[M]+\d*$/) {
+ $action="change";
+ $mode=$detail->{'mode_to'};
+ }
+ elsif ($detail->{'status'} =~ /^[AM]+\d*$/) {
+ $action="add";
+ $mode=$detail->{'mode_to'};
+ }
+ elsif ($detail->{'status'} =~ /^[DAM]+\d*/) {
+ $action="remove";
+ $mode=$detail->{'mode_from'};
+ }
+ else {
+ error "unknown status ".$detail->{'status'};
+ }
+
+ # test that the file mode is ok
+ if ($mode !~ /^100[64][64][64]$/) {
+ error sprintf(gettext("you cannot act on a file with mode %s"), $mode);
+ }
+ if ($action eq "change") {
+ if ($detail->{'mode_from'} ne $detail->{'mode_to'}) {
+ error gettext("you are not allowed to change file modes");
+ }
+ }
+
+ # extract attachment to temp file
+ if (($action eq 'add' || $action eq 'change') &&
+ ! pagetype($file)) {
+ eval q{use File::Temp};
+ die $@ if $@;
+ my $fh;
+ ($fh, $path)=File::Temp::tempfile("XXXXXXXXXX", UNLINK => 1);
+ if (system("git show ".$detail->{sha1_to}." > '$path'") != 0) {
+ error("failed writing temp file");
+ }
+ }
+
+ push @rets, {
+ file => $file,
+ action => $action,
+ path => $path,
+ };
+ }
+ }
+ }
+
+ return reverse @rets;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my @bundle=qw{
brokenlinks
img
map
- meta
+ more
orphans
pagecount
pagestats
+ progress
shortcut
smiley
tag
+ table
template
toc
toggle
- otl
+ repolist
};
-sub import { #{{{
- IkiWiki::loadplugin($_) foreach @bundle;
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "goodstuff", call => \&getsetup);
+ foreach my $plugin (@bundle) {
+ IkiWiki::loadplugin($plugin);
+ }
+}
+
+sub getsetup {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::google;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use URI;
+
+my $host;
+
+sub import {
+ hook(type => "getsetup", id => "google", call => \&getsetup);
+ hook(type => "checkconfig", id => "google", call => \&checkconfig);
+ hook(type => "pagetemplate", id => "google", call => \&pagetemplate);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig () {
+ if (! length $config{url}) {
+ error(sprintf(gettext("Must specify %s when using the %s plugin"), "url", 'google'));
+ }
+ my $uri=URI->new($config{url});
+ if (! $uri || ! defined $uri->host) {
+ error(gettext("Failed to parse url, cannot determine domain name"));
+ }
+ $host=$uri->host;
+}
+
+my $form;
+sub pagetemplate (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $template=$params{template};
+
+ # Add search box to page header.
+ if ($template->query(name => "searchform")) {
+ if (! defined $form) {
+ my $searchform = template("googleform.tmpl", blind_cache => 1);
+ $searchform->param(sitefqdn => $host);
+ $form=$searchform->output;
+ }
+
+ $template->param(searchform => $form);
+ }
+}
+
+1
+++ /dev/null
-#!/usr/bin/perl
-package IkiWiki::Plugin::googlecalendar;
-
-use warnings;
-use strict;
-use IkiWiki 2.00;
-
-sub import { #{{{
- hook(type => "preprocess", id => "googlecalendar",
- call => \&preprocess);
- hook(type => "format", id => "googlecalendar",
- call => \&format);
-} # }}}
-
-sub preprocess (@) { #{{{
- my %params=@_;
-
- # Parse the html, looking for the url to embed for the calendar.
- # 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")."]]";
- }
- my ($height)=$params{html}=~m#height="(\d+)"#;
- my ($width)=$params{html}=~m#width="(\d+)"#;
-
- return "<div class=\"googlecalendar\" src=\"$url\" height=\"$height\" width=\"$width\"></div>";
-} # }}}
-
-sub format (@) { #{{{
- my %params=@_;
-
- $params{content}=~s/<div class=\"googlecalendar" src="([^"]+)" height="([^"]+)" width="([^"]+)"><\/div>/gencal($1,$2,$3)/eg;
-
- return $params{content};
-} # }}}
-
-sub gencal ($$$) { #{{{
- my $url=shift;
- my $height=shift;
- my $width=shift;
- return qq{<iframe src="http://www.google.com/calendar/embed?$url" style=" border-width:0 " width="$width" frameborder="0" height="$height"></iframe>};
-} #}}}
-
-1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::goto;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "cgi", id => 'goto', call => \&cgi);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ }
+}
+
+# cgi_goto(CGI, [page])
+# Redirect to a specified page, or display "not found". If not specified,
+# the page param from the CGI object is used.
+sub cgi_goto ($;$) {
+ my $q = shift;
+ my $page = shift;
+
+ if (!defined $page) {
+ $page = IkiWiki::decode_utf8($q->param("page"));
+
+ if (!defined $page) {
+ error("missing page parameter");
+ }
+ }
+
+ # It's possible that $page is not a valid page name;
+ # if so attempt to turn it into one.
+ if ($page !~ /$config{wiki_file_regexp}/) {
+ $page=titlepage($page);
+ }
+
+ IkiWiki::loadindex();
+
+ # If the page is internal (like a comment), see if it has a
+ # permalink. Comments do.
+ if (IkiWiki::isinternal($page) &&
+ defined $pagestate{$page}{meta}{permalink}) {
+ IkiWiki::redirect($q, $pagestate{$page}{meta}{permalink});
+ }
+
+ my $link = bestlink("", $page);
+
+ if (! length $link) {
+ IkiWiki::cgi_custom_failure(
+ $q->header(-status => "404 Not Found"),
+ IkiWiki::misctemplate(gettext("missing page"),
+ "<p>".
+ sprintf(gettext("The page %s does not exist."),
+ htmllink("", "", $page)).
+ "</p>")
+ )
+ }
+ else {
+ IkiWiki::redirect($q, urlto($link, undef, 1));
+ }
+
+ exit;
+}
+
+sub cgi ($) {
+ my $cgi=shift;
+ my $do = $cgi->param('do');
+
+ if (defined $do && ($do eq 'goto' || $do eq 'commenter' ||
+ $do eq 'recentchanges_link')) {
+ # goto is the preferred name for this; recentchanges_link and
+ # commenter are for compatibility with any saved URLs
+ cgi_goto($cgi);
+ }
+}
+
+1;
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use IPC::Open2;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "graphviz", call => \&getsetup);
hook(type => "preprocess", id => "graph", call => \&graph);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
my %graphviz_programs = (
"dot" => 1, "neato" => 1, "fdp" => 1, "twopi" => 1, "circo" => 1
);
-sub render_graph (\%) { #{{{
+sub render_graph (\%) {
my %params = %{(shift)};
my $src = "$params{type} g {\n";
if (! -e "$config{destdir}/$dest") {
my $pid;
- my $sigpipe=0;;
+ my $sigpipe=0;
$SIG{PIPE}=sub { $sigpipe=1 };
$pid=open2(*IN, *OUT, "$params{prog} -Tpng");
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);
else {
return "<img src=\"".urlto($dest, $params{destpage})."\" />\n";
}
-} #}}}
+}
-sub graph (@) { #{{{
+sub graph (@) {
my %params=@_;
$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);
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "haiku", call => \&getsetup);
hook(type => "preprocess", id => "haiku", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
my $haiku;
$haiku=~s/\n/<br \/>\n/mg;
return "\n\n<blockquote><p>$haiku</p></blockquote>\n\n";
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::highlight;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use Encode;
+
+# locations of highlight's files
+my $filetypes="/etc/highlight/filetypes.conf";
+my $langdefdir="/usr/share/highlight/langDefs";
+
+sub import {
+ hook(type => "getsetup", id => "highlight", call => \&getsetup);
+ hook(type => "checkconfig", id => "highlight", call => \&checkconfig);
+ # this hook is used by the format plugin
+ hook(type => "htmlizefallback", id => "highlight", call =>
+ \&htmlizefallback);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+ tohighlight => {
+ type => "string",
+ example => ".c .h .cpp .pl .py Makefile:make",
+ description => "types of source files to syntax highlight",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig () {
+ if (exists $config{tohighlight}) {
+ foreach my $file (split ' ', $config{tohighlight}) {
+ my @opts = $file=~s/^\.// ?
+ (keepextension => 1) :
+ (noextension => 1);
+ my $ext = $file=~s/:(.*)// ? $1 : $file;
+
+ my $langfile=ext2langfile($ext);
+ if (! defined $langfile) {
+ error(sprintf(gettext(
+ "tohighlight contains unknown file type '%s'"),
+ $ext));
+ }
+
+ hook(
+ type => "htmlize",
+ id => $file,
+ call => sub {
+ my %params=@_;
+ highlight($langfile, $params{content});
+ },
+ longname => sprintf(gettext("Source code: %s"), $file),
+ @opts,
+ );
+ }
+ }
+}
+
+sub htmlizefallback {
+ my $format=lc shift;
+ my $langfile=ext2langfile($format);
+
+ if (! defined $langfile) {
+ return;
+ }
+
+ return Encode::decode_utf8(highlight($langfile, shift));
+}
+
+my %ext2lang;
+my $filetypes_read=0;
+my %highlighters;
+
+# Parse highlight's config file to get extension => language mappings.
+sub read_filetypes () {
+ open (IN, $filetypes);
+ while (<IN>) {
+ chomp;
+ if (/^\$ext\((.*)\)=(.*)$/) {
+ $ext2lang{$_}=$1 foreach $1, split ' ', $2;
+ }
+ }
+ close IN;
+ $filetypes_read=1;
+}
+
+
+# Given a filename extension, determines the language definition to
+# use to highlight it.
+sub ext2langfile ($) {
+ my $ext=shift;
+
+ my $langfile="$langdefdir/$ext.lang";
+ return $langfile if exists $highlighters{$langfile};
+
+ read_filetypes() unless $filetypes_read;
+ if (exists $ext2lang{$ext}) {
+ return "$langdefdir/$ext2lang{$ext}.lang";
+ }
+ # If a language only has one common extension, it will not
+ # be listed in filetypes, so check the langfile.
+ elsif (-e $langfile) {
+ return $langfile;
+ }
+ else {
+ return undef;
+ }
+}
+
+# Interface to the highlight C library.
+sub highlight ($$) {
+ my $langfile=shift;
+ my $input=shift;
+
+ eval q{use highlight};
+ if ($@) {
+ print STDERR gettext("warning: highlight perl module not available; falling back to pass through");
+ return $input;
+ }
+
+ my $gen;
+ if (! exists $highlighters{$langfile}) {
+ $gen = highlightc::CodeGenerator_getInstance($highlightc::XHTML);
+ $gen->setFragmentCode(1); # generate html fragment
+ $gen->setHTMLEnclosePreTag(1); # include stylish <pre>
+ $gen->initTheme("/dev/null"); # theme is not needed because CSS is not emitted
+ $gen->initLanguage($langfile); # must come after initTheme
+ $gen->setEncoding("utf-8");
+ $highlighters{$langfile}=$gen;
+ }
+ else {
+ $gen=$highlighters{$langfile};
+ }
+
+ return $gen->generateString($input);
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use File::Temp qw(:mktemp);
sub import {
+ hook(type => "getsetup", id => "hnb", call => \&getsetup);
hook(type => "htmlize", id => "hnb", call => \&htmlize);
}
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+}
+
sub htmlize (@) {
my %params = @_;
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "html", call => \&getsetup);
hook(type => "htmlize", id => "html", call => \&htmlize);
hook(type => "htmlize", id => "htm", call => \&htmlize);
# ikiwiki defaults to skipping .html files as a security measure;
# make it process them so this plugin can take effect
$config{wiki_file_prune_regexps} = [ grep { !m/\\\.x\?html\?\$/ } @{$config{wiki_file_prune_regexps}} ];
-} # }}}
+}
-sub htmlize (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+}
+
+sub htmlize (@) {
my %params=@_;
return $params{content};
-} #}}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::htmlbalance;
+
+# htmlbalance: Parse and re-serialize HTML to ensure balanced tags
+#
+# Copyright 2008 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+# Licensed under the GNU GPL, version 2, or any later version published by the
+# Free Software Foundation
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use HTML::Entities;
+
+sub import {
+ hook(type => "getsetup", id => "htmlbalance", call => \&getsetup);
+ hook(type => "sanitize", id => "htmlbalance", call => \&sanitize);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub sanitize (@) {
+ my %params=@_;
+ my $ret = '';
+
+ eval q{use HTML::TreeBuilder};
+ error $@ if $@;
+ my $tree = HTML::TreeBuilder->new();
+ $tree->ignore_unknown(0);
+ $tree->ignore_ignorable_whitespace(0);
+ $tree->no_space_compacting(1);
+ $tree->p_strict(1);
+ $tree->store_comments(0);
+ $tree->store_declarations(0);
+ $tree->store_pis(0);
+ $tree->parse_content($params{content});
+ my @nodes = $tree->disembowel();
+ foreach my $node (@nodes) {
+ if (ref $node) {
+ $ret .= $node->as_XML();
+ chomp $ret;
+ $node->delete();
+ }
+ else {
+ $ret .= encode_entities($node);
+ }
+ }
+ $tree->delete();
+ return $ret;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
# This regexp matches urls that are in a known safe scheme.
# Feel free to use it from other plugins.
our $safe_url_regexp;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "htmlscrubber", call => \&getsetup);
hook(type => "sanitize", id => "htmlscrubber", call => \&sanitize);
# Only known uri schemes are allowed to avoid all the ways of
# data is a special case. Allow data:image/*, but
# disallow data:text/javascript and everything else.
$safe_url_regexp=qr/^(?:(?:$uri_schemes):|data:image\/|[^:]+(?:$|\/))/i;
-} # }}}
+}
-sub sanitize (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ htmlscrubber_skip => {
+ type => "pagespec",
+ example => "!*/Discussion",
+ description => "PageSpec specifying pages not to scrub",
+ link => "ikiwiki/PageSpec",
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub sanitize (@) {
my %params=@_;
+
+ if (exists $config{htmlscrubber_skip} &&
+ length $config{htmlscrubber_skip} &&
+ exists $params{destpage} &&
+ pagespec_match($params{destpage}, $config{htmlscrubber_skip})) {
+ return $params{content};
+ }
+
return scrubber()->scrub($params{content});
-} # }}}
+}
my $_scrubber;
-sub scrubber { #{{{
+sub scrubber {
return $_scrubber if defined $_scrubber;
eval q{use HTML::Scrubber};
}],
);
return $_scrubber;
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use IPC::Open2;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "tidy", call => \&getsetup);
hook(type => "sanitize", id => "tidy", call => \&sanitize);
-} # }}}
+}
-sub sanitize (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub sanitize (@) {
my %params=@_;
my $pid;
my $sigpipe=0;
$SIG{PIPE}=sub { $sigpipe=1 };
- $pid=open2(*IN, *OUT, 'tidy -quiet -asxhtml -utf8 --show-body-only yes --show-warnings no --tidy-mark no --markup yes');
-
+ $pid=open2(*IN, *OUT, 'tidy -quiet -asxhtml -utf8 --show-body-only yes --show-warnings no --tidy-mark no --markup yes 2>/dev/null');
+
# open2 doesn't respect "use open ':utf8'"
binmode (IN, ':utf8');
- binmode (OUT, ':utf8');
+ binmode (OUT, ':utf8');
print OUT $params{content};
close OUT;
waitpid $pid, 0;
$SIG{PIPE}="DEFAULT";
- return $params{content} if $sigpipe;
+ if ($sigpipe || ! defined $ret) {
+ return gettext("htmltidy failed to parse this html");
+ }
return $ret;
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "httpauth", call => \&getsetup);
hook(type => "auth", id => "httpauth", call => \&auth);
-} # }}}
+}
-sub auth ($$) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub auth ($$) {
my $cgi=shift;
my $session=shift;
if (defined $cgi->remote_user()) {
$session->param("name", $cgi->remote_user());
}
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my %imgdefaults;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "img", call => \&getsetup);
hook(type => "preprocess", id => "img", call => \&preprocess, scan => 1);
-} #}}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my ($image) = $_[0] =~ /$config{wiki_file_regexp}/; # untaint
my %params=@_;
return '';
}
- push @{$links{$params{page}}}, $image;
+ add_link($params{page}, $image);
+
# optimisation: detect scan mode, and avoid generating the image
if (! defined wantarray) {
return;
}
my $file = bestlink($params{page}, $image);
+ my $srcfile = srcfile($file, 1);
+ if (! length $file || ! defined $srcfile) {
+ return htmllink($params{page}, $params{destpage}, $image);
+ }
my $dir = $params{page};
my $base = IkiWiki::basename($file);
eval q{use Image::Magick};
- error($@) 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})."]]"
- unless (defined $w && defined $h);
+ add_depends($params{page}, $image);
+
+ my ($w, $h) = ($params{size} =~ /^(\d*)x(\d*)$/);
+ error sprintf(gettext('wrong size format "%s" (should be WxH)'), $params{size})
+ unless (defined $w && defined $h &&
+ (length $w || length $h));
my $outfile = "$config{destdir}/$dir/${w}x${h}-$base";
$imglink = "$dir/${w}x${h}-$base";
will_render($params{page}, $imglink);
- if (-e $outfile && (-M srcfile($file) >= -M $outfile)) {
+ if (-e $outfile && (-M $srcfile >= -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;
+ $r = $im->Read($srcfile);
+ 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}) {
}
}
else {
- $r = $im->Read(srcfile($file));
- return "[[img ".sprintf(gettext("failed to read %s: %s"), $file, $r)."]]" if $r;
+ $r = $im->Read($srcfile);
+ error sprintf(gettext("failed to read %s: %s"), $file, $r) if $r;
$imglink = $file;
}
- add_depends($imglink, $params{page});
-
my ($fileurl, $imgurl);
if (! $params{preview}) {
$fileurl=urlto($file, $params{destpage});
}
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.
- '" alt="'.(exists $params{alt} ? $params{alt} : '').
'" width="'.$im->Get("width").
'" height="'.$im->Get("height").'"'.
+ (exists $params{alt} ? ' alt="'.$params{alt}.'"' : '').
(exists $params{title} ? ' title="'.$params{title}.'"' : '').
+ (exists $params{align} ? ' align="'.$params{align}.'"' : '').
(exists $params{class} ? ' class="'.$params{class}.'"' : '').
(exists $params{id} ? ' id="'.$params{id}.'"' : '').
' />';
elsif ($params{link} =~ /^\w+:\/\//) {
$imgtag='<a href="'.$params{link}.'">'.$imgtag.'</a>';
}
- elsif (length bestlink($params{page}, $params{link})) {
- add_depends($params{page}, $params{link});
- $imgtag=htmllink($params{page}, $params{destpage},
- $params{link}, linktext => $imgtag,
- noimageinline => 1);
+ else {
+ my $b = bestlink($params{page}, $params{link});
+
+ if (length $b) {
+ add_depends($params{page}, $b);
+ $imgtag=htmllink($params{page}, $params{destpage},
+ $params{link}, linktext => $imgtag,
+ noimageinline => 1);
+ }
}
if (exists $params{caption}) {
else {
return $imgtag;
}
-} #}}}
+}
1
use warnings;
use strict;
use Encode;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use URI;
my %knownfeeds;
my @inline;
my $nested=0;
-sub import { #{{{
+sub import {
hook(type => "getopt", id => "inline", call => \&getopt);
+ hook(type => "getsetup", id => "inline", call => \&getsetup);
hook(type => "checkconfig", id => "inline", call => \&checkconfig);
hook(type => "sessioncgi", id => "inline", call => \&sessioncgi);
hook(type => "preprocess", id => "inline",
call => \&IkiWiki::preprocess_inline);
hook(type => "pagetemplate", id => "inline",
call => \&IkiWiki::pagetemplate_inline);
- hook(type => "format", id => "inline", call => \&format);
+ hook(type => "format", id => "inline", call => \&format, first => 1);
# Hook to change to do pinging since it's called late.
# This ensures each page only pings once and prevents slow
# pings interrupting page builds.
- hook(type => "change", id => "inline",
- call => \&IkiWiki::pingurl);
-
-} # }}}
+ hook(type => "change", id => "inline", call => \&IkiWiki::pingurl);
+}
-sub getopt () { #{{{
+sub getopt () {
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
"atom!" => \$config{atom},
"allowrss!" => \$config{allowrss},
"allowatom!" => \$config{allowatom},
+ "pingurl=s" => sub {
+ push @{$config{pingurl}}, $_[1];
+ },
);
}
-sub checkconfig () { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ rss => {
+ type => "boolean",
+ example => 0,
+ description => "enable rss feeds by default?",
+ safe => 1,
+ rebuild => 1,
+ },
+ atom => {
+ type => "boolean",
+ example => 0,
+ description => "enable atom feeds by default?",
+ safe => 1,
+ rebuild => 1,
+ },
+ allowrss => {
+ type => "boolean",
+ example => 0,
+ description => "allow rss feeds to be used?",
+ safe => 1,
+ rebuild => 1,
+ },
+ allowatom => {
+ type => "boolean",
+ example => 0,
+ description => "allow atom feeds to be used?",
+ safe => 1,
+ rebuild => 1,
+ },
+ pingurl => {
+ type => "string",
+ example => "http://rpc.technorati.com/rpc/ping",
+ description => "urls to ping (using XML-RPC) on feed update",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
if (($config{rss} || $config{atom}) && ! length $config{url}) {
error(gettext("Must specify url to wiki with --url when using --rss or --atom"));
}
if ($config{atom}) {
push @{$config{wiki_file_prune_regexps}}, qr/\.atom$/;
}
-} #}}}
+ if (! exists $config{pingurl}) {
+ $config{pingurl}=[];
+ }
+}
-sub format (@) { #{{{
+sub format (@) {
my %params=@_;
# Fill in the inline content generated earlier. This is actually an
delete @inline[$1,]
}eg;
return $params{content};
-} #}}}
+}
-sub sessioncgi () { #{{{
+sub sessioncgi ($$) {
my $q=shift;
my $session=shift;
if ($q->param('do') eq 'blog') {
- my $page=IkiWiki::titlepage(decode_utf8($q->param('title')));
+ my $page=titlepage(decode_utf8($q->param('title')));
$page=~s/(\/)/"__".ord($1)."__"/eg; # don't create subdirs
# if the page already exists, munge it to be unique
my $from=$q->param('from');
$q->param('page', $page.$add);
# now go create the page
$q->param('do', 'create');
- IkiWiki::cgi_editpage($q, $session);
+ # make sure the editpage plugin in loaded
+ if (IkiWiki->can("cgi_editpage")) {
+ IkiWiki::cgi_editpage($q, $session);
+ }
+ else {
+ error(gettext("page editing not allowed"));
+ }
exit;
}
}
my %toping;
my %feedlinks;
-sub yesno ($) { #{{{
- my $val=shift;
- return (defined $val && lc($val) eq "yes");
-} #}}}
-
-sub preprocess_inline (@) { #{{{
+sub preprocess_inline (@) {
my %params=@_;
- if (! exists $params{pages}) {
- return "[[inline ".gettext("missing pages parameter")."]]";
+ if (! exists $params{pages} && ! exists $params{pagenames}) {
+ error gettext("missing pages parameter");
}
my $raw=yesno($params{raw});
my $archive=yesno($params{archive});
my $atom=(($config{atom} || $config{allowatom}) && exists $params{atom}) ? yesno($params{atom}) : $config{atom};
my $quick=exists $params{quick} ? yesno($params{quick}) : 0;
my $feeds=exists $params{feeds} ? yesno($params{feeds}) : !$quick;
+ my $emptyfeeds=exists $params{emptyfeeds} ? yesno($params{emptyfeeds}) : 1;
my $feedonly=yesno($params{feedonly});
if (! exists $params{show} && ! $archive) {
$params{show}=10;
}
my @list;
- foreach my $page (keys %pagesources) {
- next if $page eq $params{page};
- if (pagespec_match($page, $params{pages}, location => $params{page})) {
- push @list, $page;
+
+ if (exists $params{pagenames}) {
+ foreach my $p (qw(sort pages)) {
+ if (exists $params{$p}) {
+ error sprintf(gettext("the %s and %s parameters cannot be used together"),
+ "pagenames", $p);
+ }
}
- }
- if (exists $params{sort} && $params{sort} eq 'title') {
- @list=sort @list;
- }
- elsif (exists $params{sort} && $params{sort} eq 'mtime') {
- @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list;
- }
- elsif (! exists $params{sort} || $params{sort} eq 'age') {
- @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
+ @list = map { bestlink($params{page}, $_) }
+ split ' ', $params{pagenames};
+
+ $params{pages} = join(" or ", @list);
}
else {
- return sprintf(gettext("unknown sort type %s"), $params{sort});
+ @list = pagespec_match_list(
+ [ grep { $_ ne $params{page} } keys %pagesources ],
+ $params{pages}, location => $params{page});
+
+ if (exists $params{sort} && $params{sort} eq 'title') {
+ @list=sort { pagetitle(basename($a)) cmp pagetitle(basename($b)) } @list;
+ }
+ elsif (exists $params{sort} && $params{sort} eq 'title_natural') {
+ eval q{use Sort::Naturally};
+ if ($@) {
+ error(gettext("Sort::Naturally needed for title_natural sort"));
+ }
+ @list=sort { Sort::Naturally::ncmp(pagetitle(basename($a)), pagetitle(basename($b))) } @list;
+ }
+ elsif (exists $params{sort} && $params{sort} eq 'mtime') {
+ @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list;
+ }
+ elsif (! exists $params{sort} || $params{sort} eq 'age') {
+ @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
+ }
+ else {
+ error sprintf(gettext("unknown sort type %s"), $params{sort});
+ }
}
if (yesno($params{reverse})) {
# Explicitly add all currently displayed pages as dependencies, so
# that if they are removed or otherwise changed, the inline will be
# sure to be updated.
- add_depends($params{page}, join(" or ", $#list >= $#feedlist ? @list : @feedlist));
-
- my $feednum="";
-
- my $feedid=join("\0", map { $_."\0".$params{$_} } sort keys %params);
- if (exists $knownfeeds{$feedid}) {
- $feednum=$knownfeeds{$feedid};
+ foreach my $p ($#list >= $#feedlist ? @list : @feedlist) {
+ add_depends($params{page}, $p);
}
- else {
- if (exists $page_numfeeds{$params{destpage}}) {
- if ($feeds) {
- $feednum=$knownfeeds{$feedid}=++$page_numfeeds{$params{destpage}};
+
+ if ($feeds && exists $params{feedpages}) {
+ @feedlist=pagespec_match_list(\@feedlist, $params{feedpages}, location => $params{page});
+ }
+
+ my ($feedbase, $feednum);
+ if ($feeds) {
+ # Ensure that multiple feeds on a page go to unique files.
+
+ # Feedfile can lead to conflicts if usedirs is not enabled,
+ # so avoid supporting it in that case.
+ delete $params{feedfile} if ! $config{usedirs};
+ # Tight limits on legal feedfiles, to avoid security issues
+ # and conflicts.
+ if (defined $params{feedfile}) {
+ if ($params{feedfile} =~ /\// ||
+ $params{feedfile} !~ /$config{wiki_file_regexp}/) {
+ error("illegal feedfile");
}
+ $params{feedfile}=possibly_foolish_untaint($params{feedfile});
+ }
+ $feedbase=targetpage($params{destpage}, "", $params{feedfile});
+
+ my $feedid=join("\0", $feedbase, map { $_."\0".$params{$_} } sort keys %params);
+ if (exists $knownfeeds{$feedid}) {
+ $feednum=$knownfeeds{$feedid};
}
else {
- $feednum=$knownfeeds{$feedid}="";
- if ($feeds) {
- $page_numfeeds{$params{destpage}}=1;
+ if (exists $page_numfeeds{$params{destpage}}{$feedbase}) {
+ if ($feeds) {
+ $feednum=$knownfeeds{$feedid}=++$page_numfeeds{$params{destpage}}{$feedbase};
+ }
+ }
+ else {
+ $feednum=$knownfeeds{$feedid}="";
+ if ($feeds) {
+ $page_numfeeds{$params{destpage}}{$feedbase}=1;
+ }
}
}
}
- my $rssurl=basename(rsspage($params{destpage}).$feednum) if $feeds && $rss;
- my $atomurl=basename(atompage($params{destpage}).$feednum) if $feeds && $atom;
+ my $rssurl=abs2rel($feedbase."rss".$feednum, dirname(htmlpage($params{destpage}))) if $feeds && $rss;
+ my $atomurl=abs2rel($feedbase."atom".$feednum, dirname(htmlpage($params{destpage}))) if $feeds && $atom;
+
my $ret="";
- if ($config{cgiurl} && ! $params{preview} && (exists $params{rootpage} ||
- (exists $params{postform} && yesno($params{postform})))) {
+ if (length $config{cgiurl} && ! $params{preview} && (exists $params{rootpage} ||
+ (exists $params{postform} && yesno($params{postform}))) &&
+ IkiWiki->can("cgi_editpage")) {
# Add a blog post form, with feed buttons.
my $formtemplate=template("blogpost.tmpl", blind_cache => 1);
$formtemplate->param(cgiurl => $config{cgiurl});
- $formtemplate->param(rootpage =>
- exists $params{rootpage} ? $params{rootpage} : $params{page});
+ my $rootpage;
+ if (exists $params{rootpage}) {
+ $rootpage=bestlink($params{page}, $params{rootpage});
+ if (!length $rootpage) {
+ $rootpage=$params{rootpage};
+ }
+ }
+ else {
+ $rootpage=$params{page};
+ }
+ $formtemplate->param(rootpage => $rootpage);
$formtemplate->param(rssurl => $rssurl) if $feeds && $rss;
$formtemplate->param(atomurl => $atomurl) if $feeds && $atom;
if (exists $params{postformtext}) {
gettext("Add a new post titled:"));
}
$ret.=$formtemplate->output;
+
+ # The post form includes the feed buttons, so
+ # emptyfeeds cannot be hidden.
+ $emptyfeeds=1;
}
- elsif ($feeds && !$params{preview}) {
+ elsif ($feeds && !$params{preview} && ($emptyfeeds || @feedlist)) {
# Add feed buttons.
my $linktemplate=template("feedlink.tmpl", blind_cache => 1);
$linktemplate->param(rssurl => $rssurl) if $rss;
require HTML::Template;
my @params=IkiWiki::template_params($params{template}.".tmpl", blind_cache => 1);
if (! @params) {
- return sprintf(gettext("nonexistant template %s"), $params{template});
+ error sprintf(gettext("nonexistant template %s"), $params{template});
}
my $template=HTML::Template->new(@params) unless $raw;
my $content=get_inline_content($page, $params{destpage});
$template->param(content => $content);
}
- $template->param(pageurl => urlto(bestlink($params{page}, $page), $params{destpage}));
+ $template->param(pageurl => urlto($page, $params{destpage}));
+ $template->param(inlinepage => $page);
$template->param(title => pagetitle(basename($page)));
$template->param(ctime => displaytime($pagectime{$page}, $params{timeformat}));
+ $template->param(mtime => displaytime($pagemtime{$page}, $params{timeformat}));
$template->param(first => 1) if $page eq $list[0];
$template->param(last => 1) if $page eq $list[$#list];
my $file = $pagesources{$page};
my $type = pagetype($file);
if ($config{discussion}) {
- my $discussionlink=gettext("discussion");
- if ($page !~ /.*\/\Q$discussionlink\E$/ &&
+ if ($page !~ /.*\/\Q$config{discussionpage}\E$/ &&
(length $config{cgiurl} ||
- exists $links{$page."/".$discussionlink})) {
+ exists $links{$page."/".$config{discussionpage}})) {
$template->param(have_actions => 1);
$template->param(discussionlink =>
htmllink($page,
$params{destpage},
- gettext("Discussion"),
+ $config{discussionpage},
noimageinline => 1,
forcesubpage => 1));
}
}
}
- if ($feeds) {
- if (exists $params{feedpages}) {
- @feedlist=grep { pagespec_match($_, $params{feedpages}, location => $params{page}) } @feedlist;
- }
-
+ if ($feeds && ($emptyfeeds || @feedlist)) {
if ($rss) {
- my $rssp=rsspage($params{destpage}).$feednum;
+ my $rssp=$feedbase."rss".$feednum;
will_render($params{destpage}, $rssp);
if (! $params{preview}) {
writefile($rssp, $config{destdir},
genfeed("rss",
- $config{url}."/".rsspage($params{destpage}).$feednum, $desc, $params{destpage}, @feedlist));
+ $config{url}."/".$rssp, $desc, $params{guid}, $params{destpage}, @feedlist));
$toping{$params{destpage}}=1 unless $config{rebuild};
- $feedlinks{$params{destpage}}=qq{<link rel="alternate" type="application/rss+xml" title="RSS" href="$rssurl" />};
+ $feedlinks{$params{destpage}}.=qq{<link rel="alternate" type="application/rss+xml" title="$desc (RSS)" href="$rssurl" />};
}
}
if ($atom) {
- my $atomp=atompage($params{destpage}).$feednum;
+ my $atomp=$feedbase."atom".$feednum;
will_render($params{destpage}, $atomp);
if (! $params{preview}) {
writefile($atomp, $config{destdir},
- genfeed("atom", $config{url}."/".atompage($params{destpage}).$feednum, $desc, $params{destpage}, @feedlist));
+ genfeed("atom", $config{url}."/".$atomp, $desc, $params{guid}, $params{destpage}, @feedlist));
$toping{$params{destpage}}=1 unless $config{rebuild};
- $feedlinks{$params{destpage}}=qq{<link rel="alternate" type="application/atom+xml" title="Atom" href="$atomurl" />};
+ $feedlinks{$params{destpage}}.=qq{<link rel="alternate" type="application/atom+xml" title="$desc (Atom)" href="$atomurl" />};
}
}
}
return $ret if $raw || $nested;
push @inline, $ret;
return "<div class=\"inline\" id=\"$#inline\"></div>\n\n";
-} #}}}
+}
-sub pagetemplate_inline (@) { #{{{
+sub pagetemplate_inline (@) {
my %params=@_;
my $page=$params{page};
my $template=$params{template};
$template->param(feedlinks => $feedlinks{$page})
if exists $feedlinks{$page} && $template->query(name => "feedlinks");
-} #}}}
+}
-sub get_inline_content ($$) { #{{{
+sub get_inline_content ($$) {
my $page=shift;
my $destpage=shift;
else {
return "";
}
-} #}}}
+}
-sub date_822 ($) { #{{{
+sub date_822 ($) {
my $time=shift;
my $lc_time=POSIX::setlocale(&POSIX::LC_TIME);
my $ret=POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time));
POSIX::setlocale(&POSIX::LC_TIME, $lc_time);
return $ret;
-} #}}}
+}
-sub date_3339 ($) { #{{{
+sub date_3339 ($) {
my $time=shift;
my $lc_time=POSIX::setlocale(&POSIX::LC_TIME);
my $ret=POSIX::strftime("%Y-%m-%dT%H:%M:%SZ", gmtime($time));
POSIX::setlocale(&POSIX::LC_TIME, $lc_time);
return $ret;
-} #}}}
+}
-sub absolute_urls ($$) { #{{{
+sub absolute_urls ($$) {
# sucky sub because rss sucks
my $content=shift;
my $baseurl=shift;
$content=~s/(<a(?:\s+(?:class|id)\s*="?\w+"?)?)\s+href=\s*"(?!\w+:)(\/[^"]*)"/$1 href="$urltop$2"/mig;
$content=~s/(<img(?:\s+(?:class|id|width|height)\s*="?\w+"?)*)\s+src=\s*"(?!\w+:)(\/[^"]*)"/$1 src="$urltop$2"/mig;
return $content;
-} #}}}
-
-sub rsspage ($) { #{{{
- return targetpage(shift, "rss");
-} #}}}
-
-sub atompage ($) { #{{{
- return targetpage(shift, "atom");
-} #}}}
+}
-sub genfeed ($$$$@) { #{{{
+sub genfeed ($$$$$@) {
my $feedtype=shift;
my $feedurl=shift;
my $feeddesc=shift;
+ my $guid=shift;
my $page=shift;
my @pages=@_;
- my $url=URI->new(encode_utf8($config{url}."/".urlto($page,"")));
+ my $url=URI->new(encode_utf8(urlto($page,"",1)));
my $itemtemplate=template($feedtype."item.tmpl", blind_cache => 1);
my $content="";
my $lasttime = 0;
foreach my $p (@pages) {
- my $u=URI->new(encode_utf8($config{url}."/".urlto($p, "")));
+ my $u=URI->new(encode_utf8(urlto($p, "", 1)));
my $pcontent = absolute_urls(get_inline_content($p, $page), $url);
$itemtemplate->param(
mdate_3339 => date_3339($pagemtime{$p}),
);
+ if (exists $pagestate{$p}) {
+ if (exists $pagestate{$p}{meta}{guid}) {
+ $itemtemplate->param(guid => $pagestate{$p}{meta}{guid});
+ }
+
+ if (exists $pagestate{$p}{meta}{updated}) {
+ $itemtemplate->param(mdate_822 => date_822($pagestate{$p}{meta}{updated}));
+ $itemtemplate->param(mdate_3339 => date_3339($pagestate{$p}{meta}{updated}));
+ }
+ }
+
if ($itemtemplate->query(name => "enclosure")) {
my $file=$pagesources{$p};
my $type=pagetype($file);
pageurl => $url,
content => $content,
feeddesc => $feeddesc,
+ guid => $guid,
feeddate => date_3339($lasttime),
feedurl => $feedurl,
version => $IkiWiki::version,
});
return $template->output;
-} #}}}
+}
-sub pingurl (@) { #{{{
+sub pingurl (@) {
return unless @{$config{pingurl}} && %toping;
eval q{require RPC::XML::Client};
foreach my $page (keys %toping) {
my $title=pagetitle(basename($page), 0);
- my $url="$config{url}/".urlto($page, "");
+ my $url=urlto($page, "", 1);
foreach my $pingurl (@{$config{pingurl}}) {
debug("Pinging $pingurl for $page");
eval {
$title, $url);
my $res = $client->send_request($req);
if (! ref $res) {
- debug("Did not receive response to ping");
+ error("Did not receive response to ping");
}
my $r=$res->value;
if (! exists $r->{flerror} || $r->{flerror}) {
- debug("Ping rejected: ".(exists $r->{message} ? $r->{message} : "[unknown reason]"));
+ error("Ping rejected: ".(exists $r->{message} ? $r->{message} : "[unknown reason]"));
}
};
if ($@) {
- debug "Ping failed: $@";
+ error "Ping failed: $@";
}
}
}
exit 0; # daemon done
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my $link_regexp;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "link", call => \&getsetup);
hook(type => "checkconfig", id => "link", call => \&checkconfig);
hook(type => "linkify", id => "link", call => \&linkify);
hook(type => "scan", id => "link", call => \&scan);
-} # }}}
+ hook(type => "renamepage", id => "link", call => \&renamepage);
+}
-sub checkconfig () { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig () {
if ($config{prefix_directives}) {
$link_regexp = qr{
\[\[(?=[^!]) # beginning of link
\]\] # end of link
}x,
}
-} #}}}
+}
-sub linkify (@) { #{{{
+sub linkify (@) {
my %params=@_;
my $page=$params{page};
my $destpage=$params{destpage};
defined $2
? ( $1
? "[[$2|$3".($4 ? "#$4" : "")."]]"
- : htmllink($page, $destpage, IkiWiki::linkpage($3),
- anchor => $4, linktext => IkiWiki::pagetitle($2)))
+ : htmllink($page, $destpage, linkpage($3),
+ anchor => $4, linktext => pagetitle($2)))
: ( $1
? "[[$3".($4 ? "#$4" : "")."]]"
- : htmllink($page, $destpage, IkiWiki::linkpage($3),
+ : htmllink($page, $destpage, linkpage($3),
anchor => $4))
}eg;
return $params{content};
-} #}}}
+}
-sub scan (@) { #{{{
+sub scan (@) {
my %params=@_;
my $page=$params{page};
my $content=$params{content};
while ($content =~ /(?<!\\)$link_regexp/g) {
- push @{$links{$page}}, IkiWiki::linkpage($2);
+ add_link($page, linkpage($2));
}
-} # }}}
+}
+
+sub renamepage (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $old=$params{oldpage};
+ my $new=$params{newpage};
+
+ $params{content} =~ s{(?<!\\)$link_regexp}{
+ my $linktext=$2;
+ my $link=$linktext;
+ if (bestlink($page, linkpage($linktext)) eq $old) {
+ $link=pagetitle($new, 1);
+ $link=~s/ /_/g;
+ if ($linktext =~ m/.*\/*?[A-Z]/) {
+ # preserve leading cap of last component
+ my @bits=split("/", $link);
+ $link=join("/", @bits[0..$#bits-1], ucfirst($bits[$#bits]));
+ }
+ if (index($linktext, "/") == 0) {
+ # absolute link
+ $link="/$link";
+ }
+ }
+ defined $1
+ ? ( "[[$1|$link".($3 ? "#$3" : "")."]]" )
+ : ( "[[$link". ($3 ? "#$3" : "")."]]" )
+ }eg;
+
+ return $params{content};
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use IPC::Open2;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "linkmap", call => \&getsetup);
hook(type => "preprocess", id => "linkmap", call => \&preprocess);
hook(type => "format", id => "linkmap", call => \&format);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
my $mapnum=0;
my %maps;
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
$params{pages}="*" unless defined $params{pages};
$mapnum++;
$maps{$mapnum}=\%params;
return "<div class=\"linkmap$mapnum\"></div>";
-} # }}}
+}
-sub format (@) { #{{{
+sub format (@) {
my %params=@_;
$params{content}=~s/<div class=\"linkmap(\d+)"><\/div>/genmap($1)/eg;
return $params{content};
-} # }}}
+}
-sub genmap ($) { #{{{
+sub genmap ($) {
my $mapnum=shift;
return "" unless exists $maps{$mapnum};
my %params=%{$maps{$mapnum}};
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;
-} #}}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki listdirectives plugin.
+package IkiWiki::Plugin::listdirectives;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ add_underlay("directives");
+ hook(type => "getsetup", id => "listdirectives", call => \&getsetup);
+ hook(type => "checkconfig", id => "listdirectives", call => \&checkconfig);
+ hook(type => "needsbuild", id => "listdirectives", call => \&needsbuild);
+ hook(type => "preprocess", id => "listdirectives", call => \&preprocess);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ directive_description_dir => {
+ type => "string",
+ description => "directory in srcdir that contains directive descriptions",
+ example => "ikiwiki/directive",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+my @fulllist;
+my @shortlist;
+my $pluginstring;
+
+sub checkconfig () {
+ if (! defined $config{directive_description_dir}) {
+ $config{directive_description_dir} = "ikiwiki/directive";
+ }
+ else {
+ $config{directive_description_dir} =~ s/\/+$//;
+ }
+}
+
+sub needsbuild (@) {
+ my $needsbuild=shift;
+
+ @fulllist = grep { ! /^_/ } sort keys %{$IkiWiki::hooks{preprocess}};
+ @shortlist = grep { ! $IkiWiki::hooks{preprocess}{$_}{shortcut} } @fulllist;
+ $pluginstring = join(' ', @shortlist) . " : " . join(' ', @fulllist);
+
+ foreach my $page (keys %pagestate) {
+ if (exists $pagestate{$page}{listdirectives}{shown}) {
+ if ($pagestate{$page}{listdirectives}{shown} ne $pluginstring) {
+ push @$needsbuild, $pagesources{$page};
+ }
+ if (exists $pagesources{$page} &&
+ grep { $_ eq $pagesources{$page} } @$needsbuild) {
+ # remove state, will be re-added if
+ # the [[!listdirectives]] is still there during the
+ # rebuild
+ delete $pagestate{$page}{listdirectives}{shown};
+ }
+ }
+ }
+}
+
+sub preprocess (@) {
+ my %params=@_;
+
+ $pagestate{$params{destpage}}{listdirectives}{shown}=$pluginstring;
+
+ my @pluginlist;
+
+ if (defined $params{generated}) {
+ @pluginlist = @fulllist;
+ }
+ else {
+ @pluginlist = @shortlist;
+ }
+
+ my $result = '<ul class="listdirectives">';
+
+ foreach my $plugin (@pluginlist) {
+ $result .= '<li class="listdirectives">';
+ my $link=linkpage($config{directive_description_dir}."/".$plugin);
+ add_depends($params{page}, $link);
+ $result .= htmllink($params{page}, $params{destpage}, $link);
+ $result .= '</li>';
+ }
+
+ $result .= "</ul>";
+
+ return $result;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "lockedit", call => \&getsetup);
hook(type => "canedit", id => "lockedit", call => \&canedit);
- hook(type => "formbuilder_setup", id => "lockedit",
- call => \&formbuilder_setup);
-} # }}}
-
-sub canedit ($$) { #{{{
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ locked_pages => {
+ type => "pagespec",
+ example => "!*/Discussion",
+ description => "PageSpec controlling which pages are locked",
+ link => "ikiwiki/PageSpec",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub canedit ($$) {
my $page=shift;
my $cgi=shift;
my $session=shift;
my $user=$session->param("name");
return undef if defined $user && IkiWiki::is_admin($user);
- foreach my $admin (@{$config{adminuser}}) {
- if (pagespec_match($page, IkiWiki::userinfo_get($admin, "locked_pages"))) {
- if (! defined $user ||
- ! IkiWiki::userinfo_get($session->param("name"), "regdate")) {
- return sub { IkiWiki::needsignin($cgi, $session) };
- }
- else {
- return sprintf(gettext("%s is locked by %s and cannot be edited"),
- htmllink("", "", $page, noimageinline => 1),
- IkiWiki::userlink($admin));
- }
+ if (defined $config{locked_pages} && length $config{locked_pages} &&
+ pagespec_match($page, $config{locked_pages},
+ user => $session->param("name"),
+ ip => $ENV{REMOTE_ADDR},
+ )) {
+ if (! defined $user ||
+ ! IkiWiki::userinfo_get($session->param("name"), "regdate")) {
+ return sub { IkiWiki::needsignin($cgi, $session) };
+ }
+ else {
+ return sprintf(gettext("%s is locked and cannot be edited"),
+ htmllink("", "", $page, noimageinline => 1));
+
}
}
return undef;
-} #}}}
-
-sub formbuilder_setup (@) { #{{{
- my %params=@_;
-
- my $form=$params{form};
- if ($form->title eq "preferences") {
- my $session=$params{session};
- my $cgi=$params{cgi};
- my $user_name=$session->param("name");
-
- $form->field(name => "locked_pages", size => 50,
- fieldset => "admin",
- comment => "(".htmllink("", "", "ikiwiki/PageSpec", noimageinline => 1).")");
- if (! IkiWiki::is_admin($user_name)) {
- $form->field(name => "locked_pages", type => "hidden");
- }
- if (! $form->submitted) {
- $form->field(name => "locked_pages", force => 1,
- value => IkiWiki::userinfo_get($user_name, "locked_pages"));
- }
- if ($form->submitted && $form->submitted eq 'Save Preferences') {
- if (defined $form->field("locked_pages")) {
- IkiWiki::userinfo_set($user_name, "locked_pages",
- $form->field("locked_pages")) ||
- error("failed to set locked_pages");
- }
- }
- }
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "map", call => \&getsetup);
hook(type => "preprocess", id => "map", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
$params{pages}="*" unless defined $params{pages};
# Get all the items to map.
my %mapitems;
- foreach my $page (keys %pagesources) {
- if (pagespec_match($page, $params{pages}, location => $params{page})) {
- if (exists $params{show} &&
- exists $pagestate{$page} &&
- exists $pagestate{$page}{meta}{$params{show}}) {
- $mapitems{$page}=$pagestate{$page}{meta}{$params{show}};
- }
- else {
- $mapitems{$page}='';
- }
- # Check for a common prefix.
- if (! defined $common_prefix) {
- $common_prefix=$page;
- }
- elsif (length $common_prefix &&
- $page !~ /^\Q$common_prefix\E(\/|$)/) {
- my @a=split(/\//, $page);
- my @b=split(/\//, $common_prefix);
- $common_prefix="";
- while (@a && @b && $a[0] eq $b[0]) {
- if (length $common_prefix) {
- $common_prefix.="/";
- }
- $common_prefix.=shift(@a);
- shift @b;
+ foreach my $page (pagespec_match_list([keys %pagesources],
+ $params{pages}, location => $params{page})) {
+ if (exists $params{show} &&
+ exists $pagestate{$page} &&
+ exists $pagestate{$page}{meta}{$params{show}}) {
+ $mapitems{$page}=$pagestate{$page}{meta}{$params{show}};
+ }
+ else {
+ $mapitems{$page}='';
+ }
+ # Check for a common prefix.
+ if (! defined $common_prefix) {
+ $common_prefix=$page;
+ }
+ elsif (length $common_prefix &&
+ $page !~ /^\Q$common_prefix\E(\/|$)/) {
+ my @a=split(/\//, $page);
+ my @b=split(/\//, $common_prefix);
+ $common_prefix="";
+ while (@a && @b && $a[0] eq $b[0]) {
+ if (length $common_prefix) {
+ $common_prefix.="/";
}
+ $common_prefix.=shift(@a);
+ shift @b;
}
}
}
add_depends($params{page}, $params{pages});
# Explicitly add all currently shown pages, to detect when pages
# are removed.
- add_depends($params{page}, join(" or ", keys %mapitems));
+ foreach my $item (keys %mapitems) {
+ add_depends($params{page}, $item);
+ }
# Create the map.
my $parent="";
my $indent=0;
my $openli=0;
- my $dummy=0;
- my $map = "<div class='map'>\n<ul>\n";
+ my $addparent="";
+ my $map = "<div class='map'>\n";
+
+ # Return empty div if %mapitems is empty
+ if (!scalar(keys %mapitems)) {
+ $map .= "</div>\n";
+ return $map;
+ }
+ else { # continue populating $map
+ $map .= "<ul>\n";
+ }
+
foreach my $item (sort keys %mapitems) {
my @linktext = (length $mapitems{$item} ? (linktext => $mapitems{$item}) : ());
$item=~s/^\Q$common_prefix\E\///
my $baseitem=IkiWiki::dirname($item);
while (length $parent && length $baseitem && $baseitem !~ /^\Q$parent\E(\/|$)/) {
$parent=IkiWiki::dirname($parent);
- last if !$dummy && length $parent && $baseitem =~ /^\Q$parent\E(\/|$)/;
+ last if length $addparent && $baseitem =~ /^\Q$addparent\E(\/|$)/;
+ $addparent="";
$indent--;
$map .= "</li>\n";
if ($indent > 0) {
$map .= "</ul>\n";
}
}
- $dummy=0;
while ($depth < $indent) {
$indent--;
$map .= "</li>\n";
$map .= "<ul>\n";
}
if ($depth > $indent) {
- $dummy=1;
$p.="/".shift(@bits);
+ $addparent=$p;
+ $addparent=~s/^\///;
$map .= "<li>"
.htmllink($params{page}, $params{destpage},
- $p, class => "mapparent",
+ "/".$common_prefix.$p, class => "mapparent",
noimageinline => 1)
."\n";
$openli=1;
}
$map .= "</div>\n";
return $map;
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
- hook(type => "htmlize", id => "mdwn", call => \&htmlize);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "mdwn", call => \&getsetup);
+ hook(type => "htmlize", id => "mdwn", call => \&htmlize, longname => "Markdown");
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+ multimarkdown => {
+ type => "boolean",
+ example => 0,
+ description => "enable multimarkdown features?",
+ safe => 1,
+ rebuild => 1,
+ },
+}
my $markdown_sub;
-sub htmlize (@) { #{{{
+sub htmlize (@) {
my %params=@_;
my $content = $params{content};
if (exists $config{multimarkdown} && $config{multimarkdown}) {
eval q{use Text::MultiMarkdown};
if ($@) {
- error(gettext("multimarkdown is enabled, but Text::MultiMarkdown is not installed"));
+ debug(gettext("multimarkdown is enabled, but Text::MultiMarkdown is not installed"));
}
$markdown_sub=sub {
Text::MultiMarkdown::markdown(shift, {use_metadata => 0});
}
}
- else {
+ if (! defined $markdown_sub) {
eval q{use Text::Markdown};
if (! $@) {
if (Text::Markdown->can('markdown')) {
$content=Encode::decode_utf8($content);
return $content;
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::mercurial;
+
+use warnings;
+use strict;
+use IkiWiki;
+use Encode;
+use open qw{:utf8 :std};
+
+sub import {
+ hook(type => "checkconfig", id => "mercurial", call => \&checkconfig);
+ hook(type => "getsetup", id => "mercurial", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub checkconfig () {
+ if (exists $config{mercurial_wrapper} && length $config{mercurial_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{mercurial_wrapper},
+ wrappermode => (defined $config{mercurial_wrappermode} ? $config{mercurial_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ mercurial_wrapper => {
+ type => "string",
+ #example => # FIXME add example
+ description => "mercurial post-commit hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ mercurial_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for mercurial_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://example.com:8000/log/tip/[[file]]",
+ description => "url to hg serve'd repository, to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://localhost:8000/?fd=[[r2]];file=[[file]]",
+ description => "url to hg serve'd repository, to show diff ([[file]] and [[r2]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub mercurial_log ($) {
+ my $out = shift;
+ my @infos;
+
+ while (<$out>) {
+ my $line = $_;
+ my ($key, $value);
+
+ if (/^description:/) {
+ $key = "description";
+ $value = "";
+
+ # slurp everything as the description text
+ # until the next changeset
+ while (<$out>) {
+ if (/^changeset: /) {
+ $line = $_;
+ last;
+ }
+
+ $value .= $_;
+ }
+
+ local $/ = "";
+ chomp $value;
+ $infos[$#infos]{$key} = $value;
+ }
+
+ chomp $line;
+ ($key, $value) = split /: +/, $line, 2;
+
+ if ($key eq "changeset") {
+ push @infos, {};
+
+ # remove the revision index, which is strictly
+ # local to the repository
+ $value =~ s/^\d+://;
+ }
+
+ $infos[$#infos]{$key} = $value;
+ }
+ close $out;
+
+ return @infos;
+}
+
+sub rcs_update () {
+ my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update");
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+}
+
+sub rcs_prepedit ($) {
+ return "";
+}
+
+sub rcs_commit ($$$;$$) {
+ my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+
+ if (defined $user) {
+ $user = IkiWiki::possibly_foolish_untaint($user);
+ }
+ elsif (defined $ipaddr) {
+ $user = "Anonymous from ".IkiWiki::possibly_foolish_untaint($ipaddr);
+ }
+ else {
+ $user = "Anonymous";
+ }
+
+ $message = IkiWiki::possibly_foolish_untaint($message);
+ if (! length $message) {
+ $message = "no message given";
+ }
+
+ my @cmdline = ("hg", "-q", "-R", $config{srcdir}, "commit",
+ "-m", $message, "-u", $user);
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+
+ return undef; # success
+}
+
+sub rcs_commit_staged ($$$) {
+ # Commits all staged changes. Changes can be staged using rcs_add,
+ # rcs_remove, and rcs_rename.
+ my ($message, $user, $ipaddr)=@_;
+
+ error("rcs_commit_staged not implemented for mercurial"); # TODO
+}
+
+sub rcs_add ($) {
+ my ($file) = @_;
+
+ my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "add", "$config{srcdir}/$file");
+ if (system(@cmdline) != 0) {
+ warn "'@cmdline' failed: $!";
+ }
+}
+
+sub rcs_remove ($) {
+ my ($file) = @_;
+
+ error("rcs_remove not implemented for mercurial"); # TODO
+}
+
+sub rcs_rename ($$) {
+ my ($src, $dest) = @_;
+
+ error("rcs_rename not implemented for mercurial"); # TODO
+}
+
+sub rcs_recentchanges ($) {
+ my ($num) = @_;
+
+ my @cmdline = ("hg", "-R", $config{srcdir}, "log", "-v", "-l", $num,
+ "--style", "default");
+ open (my $out, "@cmdline |");
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+
+ my @ret;
+ foreach my $info (mercurial_log($out)) {
+ my @pages = ();
+ my @message = ();
+
+ foreach my $msgline (split(/\n/, $info->{description})) {
+ push @message, { line => $msgline };
+ }
+
+ foreach my $file (split / /,$info->{files}) {
+ my $diffurl = defined $config{diffurl} ? $config{'diffurl'} : "";
+ $diffurl =~ s/\[\[file\]\]/$file/go;
+ $diffurl =~ s/\[\[r2\]\]/$info->{changeset}/go;
+
+ push @pages, {
+ page => pagename($file),
+ diffurl => $diffurl,
+ };
+ }
+
+ my $user = $info->{"user"};
+ $user =~ s/\s*<.*>\s*$//;
+ $user =~ s/^\s*//;
+
+ push @ret, {
+ rev => $info->{"changeset"},
+ user => $user,
+ committype => "hg",
+ when => str2time($info->{"date"}),
+ message => [@message],
+ pages => [@pages],
+ };
+ }
+
+ return @ret;
+}
+
+sub rcs_diff ($) {
+ # TODO
+}
+
+sub rcs_getctime ($) {
+ my ($file) = @_;
+
+ # XXX filename passes through the shell here, should try to avoid
+ # that just in case
+ my @cmdline = ("hg", "-R", $config{srcdir}, "log", "-v",
+ "--style", "default", "$config{srcdir}/$file");
+ open (my $out, "@cmdline |");
+
+ my @log = mercurial_log($out);
+
+ if (length @log < 1) {
+ return 0;
+ }
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+
+ my $ctime = str2time($log[$#log]->{"date"});
+ return $ctime;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my %metaheaders;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "meta", call => \&getsetup);
hook(type => "needsbuild", id => "meta", call => \&needsbuild);
hook(type => "preprocess", id => "meta", call => \&preprocess, scan => 1);
hook(type => "pagetemplate", id => "meta", call => \&pagetemplate);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
-sub needsbuild (@) { #{{{
+sub needsbuild (@) {
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
if (exists $pagestate{$page}{meta}) {
}
}
-sub scrub ($) { #{{{
+sub scrub ($$) {
if (IkiWiki::Plugin::htmlscrubber->can("sanitize")) {
- return IkiWiki::Plugin::htmlscrubber::sanitize(content => shift);
+ return IkiWiki::Plugin::htmlscrubber::sanitize(
+ content => shift, destpage => shift);
}
else {
return shift;
}
-} #}}}
+}
-sub safeurl ($) { #{{{
+sub safeurl ($) {
my $url=shift;
if (exists $IkiWiki::Plugin::htmlscrubber::{safe_url_regexp} &&
defined $IkiWiki::Plugin::htmlscrubber::safe_url_regexp) {
else {
return 1;
}
-} #}}}
+}
-sub htmlize ($$$) { #{{{
+sub htmlize ($$$) {
my $page = shift;
my $destpage = shift;
IkiWiki::preprocess($page, $destpage, shift)));
}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
return "" unless @_;
my %params=@_;
my $key=shift;
$pagestate{$page}{meta}{description}=HTML::Entities::encode_numeric($value);
# fallthrough
}
+ elsif ($key eq 'guid') {
+ $pagestate{$page}{meta}{guid}=HTML::Entities::encode_numeric($value);
+ # fallthrough
+ }
elsif ($key eq 'license') {
push @{$metaheaders{$page}}, '<link rel="license" href="#page_license" />';
$pagestate{$page}{meta}{license}=$value;
}
elsif ($key eq 'link' && ! %params) {
# hidden WikiLink
- push @{$links{$page}}, $value;
+ add_link($page, $value);
return "";
}
elsif ($key eq 'author') {
$pagestate{$page}{meta}{authorurl}=$value if safeurl($value);
# fallthrough
}
+ elsif ($key eq 'date') {
+ eval q{use Date::Parse};
+ if (! $@) {
+ my $time = str2time($value);
+ $IkiWiki::pagectime{$page}=$time if defined $time;
+ }
+ }
+ elsif ($key eq 'updated') {
+ eval q{use Date::Parse};
+ if (! $@) {
+ my $time = str2time($value);
+ $pagestate{$page}{meta}{updated}=$time if defined $time;
+ }
+ }
if (! defined wantarray) {
# avoid collecting duplicate data during scan pass
}
# Metadata collection that happens only during preprocessing pass.
- if ($key eq 'date') {
- eval q{use Date::Parse};
- if (! $@) {
- my $time = str2time($value);
- $IkiWiki::pagectime{$page}=$time if defined $time;
- }
- }
- elsif ($key eq 'permalink') {
+ if ($key eq 'permalink') {
if (safeurl($value)) {
$pagestate{$page}{meta}{permalink}=$value;
- push @{$metaheaders{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />');
+ push @{$metaheaders{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />', $destpage);
}
}
elsif ($key eq 'stylesheet') {
# 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).
"\" type=\"text/css\" />";
}
elsif ($key eq 'openid') {
+ my $delegate=0; # both by default
+ if (exists $params{delegate}) {
+ $delegate = 1 if lc $params{delegate} eq 'openid';
+ $delegate = 2 if lc $params{delegate} eq 'openid2';
+ }
if (exists $params{server} && safeurl($params{server})) {
push @{$metaheaders{$page}}, '<link href="'.encode_entities($params{server}).
- '" rel="openid.server" />';
+ '" rel="openid.server" />' if $delegate ne 2;
push @{$metaheaders{$page}}, '<link href="'.encode_entities($params{server}).
- '" rel="openid2.provider" />';
+ '" rel="openid2.provider" />' if $delegate ne 1;
}
if (safeurl($value)) {
push @{$metaheaders{$page}}, '<link href="'.encode_entities($value).
- '" rel="openid.delegate" />';
+ '" rel="openid.delegate" />' if $delegate ne 2;
push @{$metaheaders{$page}}, '<link href="'.encode_entities($value).
- '" rel="openid2.local_id" />';
+ '" rel="openid2.local_id" />' if $delegate ne 1;
}
if (exists $params{"xrds-location"} && safeurl($params{"xrds-location"})) {
push @{$metaheaders{$page}}, '<meta http-equiv="X-XRDS-Location"'.
if ($value !~ /^\w+:\/\//) {
my ($redir_page, $redir_anchor) = split /\#/, $value;
- 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")
}
+ add_depends($page, $link);
$value=urlto($link, $page);
$value.='#'.$redir_anchor if defined $redir_anchor;
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};
my $delay=int(exists $params{delay} ? $params{delay} : 0);
my $redir="<meta http-equiv=\"refresh\" content=\"$delay; URL=$value\" />";
if (! $safe) {
- $redir=scrub($redir);
+ $redir=scrub($redir, $destpage);
}
push @{$metaheaders{$page}}, $redir;
}
join(" ", map {
encode_entities($_)."=\"".encode_entities(decode_entities($params{$_}))."\""
} keys %params).
- " />\n");
+ " />\n", $destpage);
}
}
elsif ($key eq 'robots') {
}
else {
push @{$metaheaders{$page}}, scrub('<meta name="'.encode_entities($key).
- '" content="'.encode_entities($value).'" />');
+ '" content="'.encode_entities($value).'" />', $destpage);
}
return "";
-} # }}}
+}
-sub pagetemplate (@) { #{{{
+sub pagetemplate (@) {
my %params=@_;
my $page=$params{page};
my $destpage=$params{destpage};
$template->param($field => htmlize($page, $destpage, $pagestate{$page}{meta}{$field}));
}
}
-} # }}}
+}
-sub match { #{{{
+sub match {
my $field=shift;
my $page=shift;
$val=$pagestate{$page}{meta}{$field};
}
elsif ($field eq 'title') {
- $val=pagetitle($page);
+ $val = pagetitle($page);
}
if (defined $val) {
else {
return IkiWiki::FailReason->new("$page does not have a $field");
}
-} #}}}
+}
package IkiWiki::PageSpec;
-sub match_title ($$;@) { #{{{
+sub match_title ($$;@) {
IkiWiki::Plugin::meta::match("title", @_);
-} #}}}
+}
-sub match_author ($$;@) { #{{{
+sub match_author ($$;@) {
IkiWiki::Plugin::meta::match("author", @_);
-} #}}}
+}
-sub match_authorurl ($$;@) { #{{{
+sub match_authorurl ($$;@) {
IkiWiki::Plugin::meta::match("authorurl", @_);
-} #}}}
+}
-sub match_license ($$;@) { #{{{
+sub match_license ($$;@) {
IkiWiki::Plugin::meta::match("license", @_);
-} #}}}
+}
-sub match_copyright ($$;@) { #{{{
+sub match_copyright ($$;@) {
IkiWiki::Plugin::meta::match("copyright", @_);
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "mirrorlist", call => \&getsetup);
hook(type => "pagetemplate", id => "mirrorlist", call => \&pagetemplate);
-} # }}}
+}
-sub pagetemplate (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ mirrorlist => {
+ type => "string",
+ example => {},
+ description => "list of mirrors",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub pagetemplate (@) {
my %params=@_;
my $template=$params{template};
- $template->param(extrafooter => mirrorlist($params{page}))
- if $template->query(name => "extrafooter");
-} # }}}
+ if ($template->query(name => "extrafooter")) {
+ my $value=$template->param("extrafooter");
+ $value.=mirrorlist($params{page});
+ $template->param(extrafooter => $value);
+ }
+}
-sub mirrorlist ($) { #{{{
+sub mirrorlist ($) {
my $page=shift;
return "<p>".
(keys %{$config{mirrorlist}} > 1 ? gettext("Mirrors") : gettext("Mirror")).
} keys %{$config{mirrorlist}}
).
"</p>";
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::monotone;
+
+use warnings;
+use strict;
+use IkiWiki;
+use Monotone;
+use Date::Parse qw(str2time);
+use Date::Format qw(time2str);
+
+my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate sha1sums
+
+sub import {
+ hook(type => "checkconfig", id => "monotone", call => \&checkconfig);
+ hook(type => "getsetup", id => "monotone", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub checkconfig () {
+ if (!defined($config{mtnrootdir})) {
+ $config{mtnrootdir} = $config{srcdir};
+ }
+ if (! -d "$config{mtnrootdir}/_MTN") {
+ error("Ikiwiki srcdir does not seem to be a Monotone workspace (or set the mtnrootdir)!");
+ }
+
+ my $child = open(MTN, "-|");
+ if (! $child) {
+ open STDERR, ">/dev/null";
+ exec("mtn", "version") || error("mtn version failed to run");
+ }
+
+ my $version=undef;
+ while (<MTN>) {
+ if (/^monotone (\d+\.\d+) /) {
+ $version=$1;
+ }
+ }
+
+ close MTN || debug("mtn version exited $?");
+
+ if (!defined($version)) {
+ error("Cannot determine monotone version");
+ }
+ if ($version < 0.38) {
+ error("Monotone version too old, is $version but required 0.38");
+ }
+
+ if (defined $config{mtn_wrapper} && length $config{mtn_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{mtn_wrapper},
+ wrappermode => (defined $config{mtn_wrappermode} ? $config{mtn_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ mtn_wrapper => {
+ type => "string",
+ example => "/srv/mtn/wiki/_MTN/ikiwiki-netsync-hook",
+ description => "monotone netsync hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ mtn_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for mtn_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ mtnkey => {
+ type => "string",
+ example => 'web@example.com',
+ description => "your monotone key",
+ safe => 1,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://viewmtn.example.com/branch/head/filechanges/com.example.branch/[[file]]",
+ description => "viewmtn url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://viewmtn.example.com/revision/diff/[[r1]]/with/[[r2]]/[[file]]",
+ description => "viewmtn url to show a diff ([[r1]], [[r2]], and [[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ mtnsync => {
+ type => "boolean",
+ example => 0,
+ description => "sync on update and commit?",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ mtnrootdir => {
+ type => "string",
+ description => "path to your workspace (defaults to the srcdir; specify if the srcdir is a subdirectory of the workspace)",
+ safe => 0, # path
+ rebuild => 0,
+ },
+}
+
+sub get_rev () {
+ my $sha1 = `mtn --root=$config{mtnrootdir} automate get_base_revision_id`;
+
+ ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now
+ if (! $sha1) {
+ debug("Unable to get base revision for '$config{srcdir}'.")
+ }
+
+ return $sha1;
+}
+
+sub get_rev_auto ($) {
+ my $automator=shift;
+
+ my @results = $automator->call("get_base_revision_id");
+
+ my $sha1 = $results[0];
+ ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now
+ if (! $sha1) {
+ debug("Unable to get base revision for '$config{srcdir}'.")
+ }
+
+ return $sha1;
+}
+
+sub mtn_merge ($$$$) {
+ my $leftRev=shift;
+ my $rightRev=shift;
+ my $branch=shift;
+ my $author=shift;
+
+ my $mergeRev;
+
+ my $child = open(MTNMERGE, "-|");
+ if (! $child) {
+ open STDERR, ">&STDOUT";
+ exec("mtn", "--root=$config{mtnrootdir}",
+ "explicit_merge", $leftRev, $rightRev,
+ $branch, "--author", $author, "--key",
+ $config{mtnkey}) || error("mtn merge failed to run");
+ }
+
+ while (<MTNMERGE>) {
+ if (/^mtn.\s.merged.\s($sha1_pattern)$/) {
+ $mergeRev=$1;
+ }
+ }
+
+ close MTNMERGE || return undef;
+
+ debug("merged $leftRev, $rightRev to make $mergeRev");
+
+ return $mergeRev;
+}
+
+sub commit_file_to_new_rev ($$$$$$$$) {
+ my $automator=shift;
+ my $wsfilename=shift;
+ my $oldFileID=shift;
+ my $newFileContents=shift;
+ my $oldrev=shift;
+ my $branch=shift;
+ my $author=shift;
+ my $message=shift;
+
+ #store the file
+ my ($out, $err) = $automator->call("put_file", $oldFileID, $newFileContents);
+ my ($newFileID) = ($out =~ m/^($sha1_pattern)$/);
+ error("Failed to store file data for $wsfilename in repository")
+ if (! defined $newFileID || length $newFileID != 40);
+
+ # get the mtn filename rather than the workspace filename
+ ($out, $err) = $automator->call("get_corresponding_path", $oldrev, $wsfilename, $oldrev);
+ my ($filename) = ($out =~ m/^file "(.*)"$/);
+ error("Couldn't find monotone repository path for file $wsfilename") if (! $filename);
+ debug("Converted ws filename of $wsfilename to repos filename of $filename");
+
+ # then stick in a new revision for this file
+ my $manifest = "format_version \"1\"\n\n".
+ "new_manifest [0000000000000000000000000000000000000000]\n\n".
+ "old_revision [$oldrev]\n\n".
+ "patch \"$filename\"\n".
+ " from [$oldFileID]\n".
+ " to [$newFileID]\n";
+ ($out, $err) = $automator->call("put_revision", $manifest);
+ my ($newRevID) = ($out =~ m/^($sha1_pattern)$/);
+ error("Unable to make new monotone repository revision")
+ if (! defined $newRevID || length $newRevID != 40);
+ debug("put revision: $newRevID");
+
+ # now we need to add certs for this revision...
+ # author, branch, changelog, date
+ $automator->call("cert", $newRevID, "author", $author);
+ $automator->call("cert", $newRevID, "branch", $branch);
+ $automator->call("cert", $newRevID, "changelog", $message);
+ $automator->call("cert", $newRevID, "date",
+ time2str("%Y-%m-%dT%T", time, "UTC"));
+
+ debug("Added certs for rev: $newRevID");
+ return $newRevID;
+}
+
+sub read_certs ($$) {
+ my $automator=shift;
+ my $rev=shift;
+ my @results = $automator->call("certs", $rev);
+ my @ret;
+
+ my $line = $results[0];
+ while ($line =~ m/\s+key\s"(.*?)"\nsignature\s"(ok|bad|unknown)"\n\s+name\s"(.*?)"\n\s+value\s"(.*?)"\n\s+trust\s"(trusted|untrusted)"\n/sg) {
+ push @ret, {
+ key => $1,
+ signature => $2,
+ name => $3,
+ value => $4,
+ trust => $5,
+ };
+ }
+
+ return @ret;
+}
+
+sub get_changed_files ($$) {
+ my $automator=shift;
+ my $rev=shift;
+
+ my @results = $automator->call("get_revision", $rev);
+ my $changes=$results[0];
+
+ my @ret;
+ my %seen = ();
+
+ while ($changes =~ m/\s*(add_file|patch|delete|rename)\s"(.*?)(?<!\\)"\n/sg) {
+ my $file = $2;
+ # don't add the same file multiple times
+ if (! $seen{$file}) {
+ push @ret, $file;
+ $seen{$file} = 1;
+ }
+ }
+
+ return @ret;
+}
+
+sub rcs_update () {
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ if (defined($config{mtnsync}) && $config{mtnsync}) {
+ if (system("mtn", "--root=$config{mtnrootdir}", "sync",
+ "--quiet", "--ticker=none",
+ "--key", $config{mtnkey}) != 0) {
+ debug("monotone sync failed before update");
+ }
+ }
+
+ if (system("mtn", "--root=$config{mtnrootdir}", "update", "--quiet") != 0) {
+ debug("monotone update failed");
+ }
+}
+
+sub rcs_prepedit ($) {
+ my $file=shift;
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ # For monotone, return the revision of the file when
+ # editing begins.
+ return get_rev();
+}
+
+sub rcs_commit ($$$;$$) {
+ # Tries to commit the page; returns undef on _success_ and
+ # a version of the page with the rcs's conflict markers on failure.
+ # The file is relative to the srcdir.
+ my $file=shift;
+ my $message=shift;
+ my $rcstoken=shift;
+ my $user=shift;
+ my $ipaddr=shift;
+ my $author;
+
+ if (defined $user) {
+ $author="Web user: " . $user;
+ }
+ elsif (defined $ipaddr) {
+ $author="Web IP: " . $ipaddr;
+ }
+ else {
+ $author="Web: Anonymous";
+ }
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ my ($oldrev)= $rcstoken=~ m/^($sha1_pattern)$/; # untaint
+ my $rev = get_rev();
+ if (defined $rev && defined $oldrev && $rev ne $oldrev) {
+ my $automator = Monotone->new();
+ $automator->open_args("--root", $config{mtnrootdir}, "--key", $config{mtnkey});
+
+ # Something has been committed, has this file changed?
+ my ($out, $err);
+ $automator->setOpts("r", $oldrev, "r", $rev);
+ ($out, $err) = $automator->call("content_diff", $file);
+ debug("Problem committing $file") if ($err ne "");
+ my $diff = $out;
+
+ if ($diff) {
+ # Commit a revision with just this file changed off
+ # the old revision.
+ #
+ # first get the contents
+ debug("File changed: forming branch");
+ my $newfile=readfile("$config{srcdir}/$file");
+
+ # then get the old content ID from the diff
+ if ($diff !~ m/^---\s$file\s+($sha1_pattern)$/m) {
+ error("Unable to find previous file ID for $file");
+ }
+ my $oldFileID = $1;
+
+ # get the branch we're working in
+ ($out, $err) = $automator->call("get_option", "branch");
+ chomp $out;
+ error("Illegal branch name in monotone workspace") if ($out !~ m/^([-\@\w\.]+)$/);
+ my $branch = $1;
+
+ # then put the new content into the DB (and record the new content ID)
+ my $newRevID = commit_file_to_new_rev($automator, $file, $oldFileID, $newfile, $oldrev, $branch, $author, $message);
+
+ $automator->close();
+
+ # if we made it to here then the file has been committed... revert the local copy
+ if (system("mtn", "--root=$config{mtnrootdir}", "revert", $file) != 0) {
+ debug("Unable to revert $file after merge on conflicted commit!");
+ }
+ debug("Divergence created! Attempting auto-merge.");
+
+ # see if it will merge cleanly
+ $ENV{MTN_MERGE}="fail";
+ my $mergeResult = mtn_merge($newRevID, $rev, $branch, $author);
+ $ENV{MTN_MERGE}="";
+
+ # push any changes so far
+ if (defined($config{mtnsync}) && $config{mtnsync}) {
+ if (system("mtn", "--root=$config{mtnrootdir}", "push", "--quiet", "--ticker=none", "--key", $config{mtnkey}) != 0) {
+ debug("monotone push failed");
+ }
+ }
+
+ if (defined($mergeResult)) {
+ # everything is merged - bring outselves up to date
+ if (system("mtn", "--root=$config{mtnrootdir}",
+ "update", "-r", $mergeResult) != 0) {
+ debug("Unable to update to rev $mergeResult after merge on conflicted commit!");
+ }
+ }
+ else {
+ debug("Auto-merge failed. Using diff-merge to add conflict markers.");
+
+ $ENV{MTN_MERGE}="diffutils";
+ $ENV{MTN_MERGE_DIFFUTILS}="partial=true";
+ $mergeResult = mtn_merge($newRevID, $rev, $branch, $author);
+ $ENV{MTN_MERGE}="";
+ $ENV{MTN_MERGE_DIFFUTILS}="";
+
+ if (!defined($mergeResult)) {
+ debug("Unable to insert conflict markers!");
+ error("Your commit succeeded. Unfortunately, someone else committed something to the same ".
+ "part of the wiki at the same time. Both versions are stored in the monotone repository, ".
+ "but at present the different versions cannot be reconciled through the web interface. ".
+ "Please use the non-web interface to resolve the conflicts.");
+ }
+
+ if (system("mtn", "--root=$config{mtnrootdir}",
+ "update", "-r", $mergeResult) != 0) {
+ debug("Unable to update to rev $mergeResult after conflict-enhanced merge on conflicted commit!");
+ }
+
+ # return "conflict enhanced" file to the user
+ # for cleanup note, this relies on the fact
+ # that ikiwiki seems to call rcs_prepedit()
+ # again after we return
+ return readfile("$config{srcdir}/$file");
+ }
+ return undef;
+ }
+ $automator->close();
+ }
+
+ # If we reached here then the file we're looking at hasn't changed
+ # since $oldrev. Commit it.
+
+ if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
+ "--author", $author, "--key", $config{mtnkey}, "-m",
+ IkiWiki::possibly_foolish_untaint($message), $file) != 0) {
+ debug("Traditional commit failed! Returning data as conflict.");
+ my $conflict=readfile("$config{srcdir}/$file");
+ if (system("mtn", "--root=$config{mtnrootdir}", "revert",
+ "--quiet", $file) != 0) {
+ debug("monotone revert failed");
+ }
+ return $conflict;
+ }
+ if (defined($config{mtnsync}) && $config{mtnsync}) {
+ if (system("mtn", "--root=$config{mtnrootdir}", "push",
+ "--quiet", "--ticker=none", "--key",
+ $config{mtnkey}) != 0) {
+ debug("monotone push failed");
+ }
+ }
+
+ return undef # success
+}
+
+sub rcs_commit_staged ($$$) {
+ # Commits all staged changes. Changes can be staged using rcs_add,
+ # rcs_remove, and rcs_rename.
+ my ($message, $user, $ipaddr)=@_;
+
+ # Note - this will also commit any spurious changes that happen to be
+ # lying around in the working copy. There shouldn't be any, but...
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ my $author;
+
+ if (defined $user) {
+ $author="Web user: " . $user;
+ }
+ elsif (defined $ipaddr) {
+ $author="Web IP: " . $ipaddr;
+ }
+ else {
+ $author="Web: Anonymous";
+ }
+
+ if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
+ "--author", $author, "--key", $config{mtnkey}, "-m",
+ IkiWiki::possibly_foolish_untaint($message)) != 0) {
+ error("Monotone commit failed");
+ }
+}
+
+sub rcs_add ($) {
+ my $file=shift;
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ if (system("mtn", "--root=$config{mtnrootdir}", "add", "--quiet",
+ $file) != 0) {
+ error("Monotone add failed");
+ }
+}
+
+sub rcs_remove ($) {
+ my $file = shift;
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ # Note: it is difficult to undo a remove in Monotone at the moment.
+ # Until this is fixed, it might be better to make 'rm' move things
+ # into an attic, rather than actually remove them.
+ # To resurrect a file, you currently add a new file with the contents
+ # you want it to have. This loses all connectivity and automated
+ # merging with the 'pre-delete' versions of the file.
+
+ if (system("mtn", "--root=$config{mtnrootdir}", "rm", "--quiet",
+ $file) != 0) {
+ error("Monotone remove failed");
+ }
+}
+
+sub rcs_rename ($$) {
+ my ($src, $dest) = @_;
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ if (system("mtn", "--root=$config{mtnrootdir}", "rename", "--quiet",
+ $src, $dest) != 0) {
+ error("Monotone rename failed");
+ }
+}
+
+sub rcs_recentchanges ($) {
+ my $num=shift;
+ my @ret;
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ # use log --brief to get a list of revs, as this
+ # gives the results in a nice order
+ # (otherwise we'd have to do our own date sorting)
+
+ my @revs;
+
+ my $child = open(MTNLOG, "-|");
+ if (! $child) {
+ exec("mtn", "log", "--root=$config{mtnrootdir}", "--no-graph",
+ "--brief", "--last=$num") || error("mtn log failed to run");
+ }
+
+ while (my $line = <MTNLOG>) {
+ if ($line =~ m/^($sha1_pattern)/) {
+ push @revs, $1;
+ }
+ }
+ close MTNLOG || debug("mtn log exited $?");
+
+ my $automator = Monotone->new();
+ $automator->open(undef, $config{mtnrootdir});
+
+ while (@revs != 0) {
+ my $rev = shift @revs;
+ # first go through and figure out the messages, etc
+
+ my $certs = [read_certs($automator, $rev)];
+
+ my $user;
+ my $when;
+ my $committype;
+ my (@pages, @message);
+
+ foreach my $cert (@$certs) {
+ if ($cert->{signature} eq "ok" &&
+ $cert->{trust} eq "trusted") {
+ if ($cert->{name} eq "author") {
+ $user = $cert->{value};
+ # detect the source of the commit
+ # from the changelog
+ if ($cert->{key} eq $config{mtnkey}) {
+ $committype = "web";
+ } else {
+ $committype = "mtn";
+ }
+ } elsif ($cert->{name} eq "date") {
+ $when = str2time($cert->{value}, 'UTC');
+ } elsif ($cert->{name} eq "changelog") {
+ my $messageText = $cert->{value};
+ # split the changelog into multiple
+ # lines
+ foreach my $msgline (split(/\n/, $messageText)) {
+ push @message, { line => $msgline };
+ }
+ }
+ }
+ }
+
+ my @changed_files = get_changed_files($automator, $rev);
+
+ my ($out, $err) = $automator->call("parents", $rev);
+ my @parents = ($out =~ m/^($sha1_pattern)$/);
+ my $parent = $parents[0];
+
+ foreach my $file (@changed_files) {
+ next unless length $file;
+
+ if (defined $config{diffurl} and (@parents == 1)) {
+ my $diffurl=$config{diffurl};
+ $diffurl=~s/\[\[r1\]\]/$parent/g;
+ $diffurl=~s/\[\[r2\]\]/$rev/g;
+ $diffurl=~s/\[\[file\]\]/$file/g;
+ push @pages, {
+ page => pagename($file),
+ diffurl => $diffurl,
+ };
+ }
+ else {
+ push @pages, {
+ page => pagename($file),
+ }
+ }
+ }
+
+ push @ret, {
+ rev => $rev,
+ user => $user,
+ committype => $committype,
+ when => $when,
+ message => [@message],
+ pages => [@pages],
+ } if @pages;
+ }
+
+ $automator->close();
+
+ return @ret;
+}
+
+sub rcs_diff ($) {
+ my $rev=shift;
+ my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ my $child = open(MTNDIFF, "-|");
+ if (! $child) {
+ exec("mtn", "diff", "--root=$config{mtnrootdir}", "-r", "p:".$sha1, "-r", $sha1) || error("mtn diff $sha1 failed to run");
+ }
+
+ my (@lines) = <MTNDIFF>;
+
+ close MTNDIFF || debug("mtn diff $sha1 exited $?");
+
+ if (wantarray) {
+ return @lines;
+ }
+ else {
+ return join("", @lines);
+ }
+}
+
+sub rcs_getctime ($) {
+ my $file=shift;
+
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+
+ my $child = open(MTNLOG, "-|");
+ if (! $child) {
+ exec("mtn", "log", "--root=$config{mtnrootdir}", "--no-graph",
+ "--brief", $file) || error("mtn log $file failed to run");
+ }
+
+ my $firstRev;
+ while (<MTNLOG>) {
+ if (/^($sha1_pattern)/) {
+ $firstRev=$1;
+ }
+ }
+ close MTNLOG || debug("mtn log $file exited $?");
+
+ if (! defined $firstRev) {
+ debug "failed to parse mtn log for $file";
+ return 0;
+ }
+
+ my $automator = Monotone->new();
+ $automator->open(undef, $config{mtnrootdir});
+
+ my $certs = [read_certs($automator, $firstRev)];
+
+ $automator->close();
+
+ my $date;
+
+ foreach my $cert (@$certs) {
+ if ($cert->{signature} eq "ok" && $cert->{trust} eq "trusted") {
+ if ($cert->{name} eq "date") {
+ $date = $cert->{value};
+ }
+ }
+ }
+
+ if (! defined $date) {
+ debug "failed to find date cert for revision $firstRev when looking for creation time of $file";
+ return 0;
+ }
+
+ $date=str2time($date, 'UTC');
+ debug("found ctime ".localtime($date)." for $file");
+ return $date;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my $linktext = gettext("more");
-sub import { #{{{
- hook(type => "preprocess", id => "more", call => \&preprocess);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "more", call => \&getsetup);
+ hook(type => "preprocess", id => "more", call => \&preprocess);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
$params{linktext} = $linktext unless defined $params{linktext};
--- /dev/null
+#!/usr/bin/perl
+# Stubs for no revision control.
+package IkiWiki::Plugin::norcs;
+
+use warnings;
+use strict;
+use IkiWiki;
+
+sub import {
+ hook(type => "getsetup", id => "norcs", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => 0,
+ },
+}
+
+
+sub rcs_update () {
+}
+
+sub rcs_prepedit ($) {
+ return ""
+}
+
+sub rcs_commit ($$$;$$) {
+ my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
+ return undef # success
+}
+
+sub rcs_commit_staged ($$$) {
+ my ($message, $user, $ipaddr)=@_;
+ return undef # success
+}
+
+sub rcs_add ($) {
+}
+
+sub rcs_remove ($) {
+}
+
+sub rcs_rename ($$) {
+}
+
+sub rcs_recentchanges ($) {
+}
+
+sub rcs_diff ($) {
+}
+
+sub rcs_getctime ($) {
+ error gettext("getctime not implemented");
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "opendiscussion", call => \&getsetup);
hook(type => "canedit", id => "opendiscussion", call => \&canedit);
-} # }}}
+}
-sub canedit ($$) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub canedit ($$) {
my $page=shift;
my $cgi=shift;
my $session=shift;
- my $discussion=gettext("discussion");
- return "" if $page=~/(\/|^)\Q$discussion\E$/;
+ return "" if $page=~/(\/|^)\Q$config{discussionpage}\E$/;
return undef;
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
hook(type => "getopt", id => "openid", call => \&getopt);
+ hook(type => "getsetup", id => "openid", call => \&getsetup);
hook(type => "auth", id => "openid", call => \&auth);
hook(type => "formbuilder_setup", id => "openid",
call => \&formbuilder_setup, last => 1);
-} # }}}
+}
-sub getopt () { #{{{
+sub getopt () {
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
GetOptions("openidsignup=s" => \$config{openidsignup});
-} #}}}
+}
-sub formbuilder_setup (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ openidsignup => {
+ type => "string",
+ example => "http://myopenid.com/",
+ description => "an url where users can signup for an OpenID",
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub formbuilder_setup (@) {
my %params=@_;
my $form=$params{form};
# needing to depend on it.
eval q{use Net::OpenID::Consumer};
if ($@) {
- debug("unable to load Net::OpenID::Consumer, not enabling OpenID login");
+ debug("unable to load Net::OpenID::Consumer, not enabling OpenID login ($@)");
return;
}
}
}
-sub validate ($$$;$) { #{{{
+sub validate ($$$;$) {
my $q=shift;
my $session=shift;
my $openid_url=shift;
# eventually bounce them back to auth()
IkiWiki::redirect($q, $check_url);
exit 0;
-} #}}}
+}
-sub auth ($$) { #{{{
+sub auth ($$) {
my $q=shift;
my $session=shift;
# myopenid.com affiliate support
validate($q, $session, $q->param('openid_identifier'));
}
-} #}}}
+}
-sub getobj ($$) { #{{{
+sub getobj ($$) {
my $q=shift;
my $session=shift;
consumer_secret => sub { return shift()+$secret },
required_root => $config{cgiurl},
);
-} #}}}
-
-package IkiWiki;
-
-# This is not used by this plugin, but this seems the best place to put it.
-# Used elsewhere to pretty-display the name of an openid user.
-sub openiduser ($) { #{{{
- my $user=shift;
-
- if ($user =~ m!^https?://! &&
- eval q{use Net::OpenID::VerifiedIdentity; 1} && !$@) {
- my $oid=Net::OpenID::VerifiedIdentity->new(identity => $user);
- my $display=$oid->display;
- # Convert "user.somehost.com" to "user [somehost.com]".
- if ($display !~ /\[/) {
- $display=~s/^(.*?)\.([^.]+\.[a-z]+)$/$1 [$2]/;
- }
- # Convert "http://somehost.com/user" to "user [somehost.com]".
- if ($display !~ /\[/) {
- $display=~s/^https?:\/\/(.+)\/([^\/]+)$/$2 [$1]/;
- }
- $display=~s!^https?://!!; # make sure this is removed
- eval q{use CGI 'escapeHTML'};
- error($@) if $@;
- return escapeHTML($display);
- }
- return;
}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "orphans", call => \&getsetup);
hook(type => "preprocess", id => "orphans", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
$params{pages}="*" unless defined $params{pages};
# register a dependency.
add_depends($params{page}, $params{pages});
- my %linkedto;
- foreach my $p (keys %links) {
- map { $linkedto{bestlink($p, $_)}=1 if length $_ }
- @{$links{$p}};
- }
-
my @orphans;
- my $discussion=gettext("discussion");
- foreach my $page (keys %pagesources) {
- next if $linkedto{$page} || $page eq 'index';
- next unless pagespec_match($page, $params{pages}, location => $params{page});
+ foreach my $page (pagespec_match_list(
+ [ grep { ! IkiWiki::backlink_pages($_) && $_ ne 'index' }
+ keys %pagesources ],
+ $params{pages}, location => $params{page})) {
# If the page has a link to some other page, it's
# indirectly linked to a page via that page's backlinks.
next if grep {
length $_ &&
- ($_ !~ /\/\Q$discussion\E$/i || ! $config{discussion}) &&
- bestlink($page, $_) !~ /^($page|)$/
+ ($_ !~ /\/\Q$config{discussionpage}\E$/i || ! $config{discussion}) &&
+ bestlink($page, $_) !~ /^(\Q$page\E|)$/
} @{$links{$page}};
push @orphans, $page;
}
- return gettext("All pages are linked to by other pages.") unless @orphans;
+ return gettext("All pages have other pages linking to them.") unless @orphans;
return "<ul>\n".
join("\n",
map {
"</li>"
} sort @orphans).
"</ul>\n";
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
+use open qw{:utf8 :std};
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "otl", call => \&getsetup);
hook(type => "filter", id => "otl", call => \&filter);
hook(type => "htmlize", id => "otl", call => \&htmlize);
-} # }}}
+}
-sub filter (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+}
+
+sub filter (@) {
my %params=@_;
# Munge up check boxes to look a little bit better. This is a hack.
$params{content}=~s/^(\s*)\[_\]\s/${1}$unchecked /mg;
return $params{content};
-} # }}}
+}
-sub htmlize (@) { #{{{
+sub htmlize (@) {
my %params=@_;
# Can't use open2 since otl2html doesn't play nice with buffering.
$ret=~s/<body>.*//s;
$ret=~s/<div class="Footer">.*//s;
return $ret;
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "pagecount", call => \&getsetup);
hook(type => "preprocess", id => "pagecount", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
$params{pages}="*" unless defined $params{pages};
# register a dependency.
add_depends($params{page}, $params{pages});
- my @pages=keys %pagesources;
- return $#pages+1 if $params{pages} eq "*"; # optimisation
- my $count=0;
- foreach my $page (@pages) {
- $count++ if pagespec_match($page, $params{pages}, location => $params{page});
+ my @pages;
+ if ($params{pages} eq "*") {
+ @pages=keys %pagesources;
+ }
+ else {
+ @pages=pagespec_match_list([keys %pagesources], $params{pages}, location => $params{page});
}
- return $count;
-} # }}}
+ return $#pages+1;
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
# Names of the HTML classes to use for the tag cloud
our @classes = ('smallestPC', 'smallPC', 'normalPC', 'bigPC', 'biggestPC' );
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "pagestats", call => \&getsetup);
hook(type => "preprocess", id => "pagestats", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
$params{pages}="*" unless defined $params{pages};
my $style = ($params{style} or 'cloud');
# Needs to update whenever a page is added or removed, so
# register a dependency.
add_depends($params{page}, $params{pages});
+ add_depends($params{page}, $params{among}) if exists $params{among};
my %counts;
my $max = 0;
- foreach my $page (keys %links) {
- if (pagespec_match($page, $params{pages}, location => $params{page})) {
- use IkiWiki::Render;
- $counts{$page} = scalar(IkiWiki::backlinks($page));
- $max = $counts{$page} if $counts{$page} > $max;
+ foreach my $page (pagespec_match_list([keys %links],
+ $params{pages}, location => $params{page})) {
+ use IkiWiki::Render;
+
+ my @backlinks = IkiWiki::backlink_pages($page);
+
+ if (exists $params{among}) {
+ @backlinks = pagespec_match_list(\@backlinks,
+ $params{among}, location => $params{page});
}
+
+ $counts{$page} = scalar(@backlinks);
+ $max = $counts{$page} if $counts{$page} > $max;
}
if ($style eq 'table') {
my $res = "<div class='pagecloud'>\n";
foreach my $page (sort keys %counts) {
+ next unless $counts{$page} > 0;
+
my $class = $classes[$counts{$page} * scalar(@classes) / ($max + 1)];
$res .= "<span class=\"$class\">".
htmllink($params{page}, $params{destpage}, $page).
return $res;
}
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my %templates;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "pagetemplate", call => \&getsetup);
hook(type => "preprocess", id => "pagetemplate", call => \&preprocess);
hook(type => "templatefile", id => "pagetemplate", call => \&templatefile);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
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}) {
}
return "";
-} # }}}
+}
-sub templatefile (@) { #{{{
+sub templatefile (@) {
my %params=@_;
if (exists $templates{$params{page}}) {
}
return undef;
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki parentlinks plugin.
+package IkiWiki::Plugin::parentlinks;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "parentlinks", id => "parentlinks", call => \&parentlinks);
+ hook(type => "pagetemplate", id => "parentlinks", call => \&pagetemplate);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub parentlinks ($) {
+ my $page=shift;
+
+ my @ret;
+ my $path="";
+ my $title=$config{wikiname};
+ my $i=0;
+ my $depth=0;
+ my $height=0;
+
+ my @pagepath=(split("/", $page));
+ my $pagedepth=@pagepath;
+ foreach my $dir (@pagepath) {
+ next if $dir eq 'index';
+ $depth=$i;
+ $height=($pagedepth - $depth);
+ push @ret, {
+ url => urlto(bestlink($page, $path), $page),
+ page => $title,
+ depth => $depth,
+ height => $height,
+ "depth_$depth" => 1,
+ "height_$height" => 1,
+ };
+ $path.="/".$dir;
+ $title=pagetitle($dir);
+ $i++;
+ }
+ return @ret;
+}
+
+sub pagetemplate (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $template=$params{template};
+
+ if ($template->query(name => "parentlinks")) {
+ $template->param(parentlinks => [parentlinks($page)]);
+ }
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
- hook(type => "formbuilder_setup", id => "passwordauth",
- call => \&formbuilder_setup);
- hook(type => "formbuilder", id => "passwordauth",
- call => \&formbuilder);
+sub import {
+ hook(type => "getsetup", id => "passwordauth", "call" => \&getsetup);
+ hook(type => "formbuilder_setup", id => "passwordauth", call => \&formbuilder_setup);
+ hook(type => "formbuilder", id => "passwordauth", call => \&formbuilder);
hook(type => "sessioncgi", id => "passwordauth", call => \&sessioncgi);
-} # }}}
+ hook(type => "auth", id => "passwordauth", call => \&auth);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ account_creation_password => {
+ type => "string",
+ example => "s3cr1t",
+ description => "a password that must be entered when signing up for an account",
+ safe => 1,
+ rebuild => 0,
+ },
+ password_cost => {
+ type => "integer",
+ example => 8,
+ description => "cost of generating a password using Authen::Passphrase::BlowfishCrypt",
+ safe => 1,
+ rebuild => 0,
+ },
+}
# Checks if a string matches a user's password, and returns true or false.
-sub checkpassword ($$;$) { #{{{
+sub checkpassword ($$;$) {
my $user=shift;
my $password=shift;
my $field=shift || "password";
}
return $ret;
-} #}}}
+}
-sub setpassword ($$;$) { #{{{
+sub setpassword ($$;$) {
my $user=shift;
my $password=shift;
my $field=shift || "password";
else {
IkiWiki::userinfo_set($user, $field, $password);
}
-} #}}}
+}
-sub formbuilder_setup (@) { #{{{
+sub formbuilder_setup (@) {
my %params=@_;
my $form=$params{form};
if ($form->submitted eq "Register" || $form->submitted eq "Create Account") {
$form->field(name => "confirm_password", type => "password");
- $form->field(name => "account_creation_password", type => "password") if (length $config{account_creation_password});
+ $form->field(name => "account_creation_password", type => "password")
+ if (defined $config{account_creation_password} &&
+ length $config{account_creation_password});
$form->field(name => "email", size => 50);
$form->title("register");
$form->text("");
shift eq $config{account_creation_password};
},
required => 1,
- ) if (length $config{account_creation_password});
+ ) if (defined $config{account_creation_password} &&
+ length $config{account_creation_password});
$form->field(
name => "email",
validate => "EMAIL",
}
}
-sub formbuilder (@) { #{{{
+sub formbuilder (@) {
my %params=@_;
my $form=$params{form};
error($@) if $@;
sendmail(
To => IkiWiki::userinfo_get($user_name, "email"),
- From => "$config{wikiname} admin <$config{adminemail}>",
+ From => "$config{wikiname} admin <".
+ (defined $config{adminemail} ? $config{adminemail} : "")
+ .">",
Subject => "$config{wikiname} information",
Message => $template->output,
) or error(gettext("Failed to send mail"));
}
}
}
-} #}}}
+}
-sub sessioncgi ($$) { #{{{
+sub sessioncgi ($$) {
my $q=shift;
my $session=shift;
IkiWiki::cgi_prefs($q, $session);
exit;
}
-} #}}}
+}
+
+sub auth ($$) {
+ # While this hook is not currently used, it needs to exist
+ # so ikiwiki knows that the wiki supports logins, and will
+ # enable the Preferences page.
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
- hook(type => "cgi", id => "aggregate", call => \&cgi);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "pingee", call => \&getsetup);
+ hook(type => "cgi", id => "pingee", call => \&cgi);
+}
-sub cgi ($) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub cgi ($) {
my $cgi=shift;
if (defined $cgi->param('do') && $cgi->param("do") eq "ping") {
IkiWiki::saveindex();
exit 0;
}
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my %pages;
my $pinged=0;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "pinger", call => \&getsetup);
hook(type => "needsbuild", id => "pinger", call => \&needsbuild);
hook(type => "preprocess", id => "ping", call => \&preprocess);
hook(type => "delete", id => "pinger", call => \&ping);
hook(type => "change", id => "pinger", call => \&ping);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ pinger_timeout => {
+ type => "integer",
+ example => 15,
+ description => "how many seconds to try pinging before timing out",
+ safe => 1,
+ rebuild => 0,
+ },
+}
-sub needsbuild (@) { #{{{
+sub needsbuild (@) {
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
if (exists $pagestate{$page}{pinger}) {
}
}
}
-} # }}}
+}
-sub preprocess (@) { #{{{
+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;
else {
return sprintf(gettext("Ignoring ping directive for wiki %s (this wiki is %s)"), $params{from}, $config{url});
}
-} # }}}
+}
sub ping {
if (! $pinged && %pages) {
# will still be avoided.
next if $url=~/^\Q$config{cgiurl}\E/;
- $ua->head($url);
+ $ua->get($url);
}
exit 0;
--- /dev/null
+#!/usr/bin/perl
+# .po as a wiki page type
+# Licensed under GPL v2 or greater
+# Copyright (C) 2008-2009 intrigeri <intrigeri@boum.org>
+# inspired by the GPL'd po4a-translate,
+# which is Copyright 2002, 2003, 2004 by Martin Quinson (mquinson#debian.org)
+package IkiWiki::Plugin::po;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use Encode;
+eval q{use Locale::Po4a::Common qw(nowrapi18n !/.*/)};
+if ($@) {
+ print STDERR gettext("warning: Old po4a detected! Recommend upgrade to 0.35.")."\n";
+ eval q{use Locale::Po4a::Common qw(!/.*/)};
+ die $@ if $@;
+}
+use Locale::Po4a::Chooser;
+use Locale::Po4a::Po;
+use File::Basename;
+use File::Copy;
+use File::Spec;
+use File::Temp;
+use Memoize;
+use UNIVERSAL;
+
+my %translations;
+my @origneedsbuild;
+my %origsubs;
+
+memoize("istranslatable");
+memoize("_istranslation");
+memoize("percenttranslated");
+
+sub import {
+ hook(type => "getsetup", id => "po", call => \&getsetup);
+ hook(type => "checkconfig", id => "po", call => \&checkconfig);
+ hook(type => "needsbuild", id => "po", call => \&needsbuild);
+ hook(type => "scan", id => "po", call => \&scan, last => 1);
+ hook(type => "filter", id => "po", call => \&filter);
+ hook(type => "htmlize", id => "po", call => \&htmlize);
+ hook(type => "pagetemplate", id => "po", call => \&pagetemplate, last => 1);
+ hook(type => "rename", id => "po", call => \&renamepages, first => 1);
+ hook(type => "delete", id => "po", call => \&mydelete);
+ hook(type => "change", id => "po", call => \&change);
+ hook(type => "checkcontent", id => "po", call => \&checkcontent);
+ hook(type => "canremove", id => "po", call => \&canremove);
+ hook(type => "canrename", id => "po", call => \&canrename);
+ hook(type => "editcontent", id => "po", call => \&editcontent);
+ hook(type => "formbuilder_setup", id => "po", call => \&formbuilder_setup, last => 1);
+ hook(type => "formbuilder", id => "po", call => \&formbuilder);
+
+ $origsubs{'beautify_urlpath'}=\&IkiWiki::beautify_urlpath;
+ inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath);
+ $origsubs{'targetpage'}=\&IkiWiki::targetpage;
+ inject(name => "IkiWiki::targetpage", call => \&mytargetpage);
+ $origsubs{'urlto'}=\&IkiWiki::urlto;
+ inject(name => "IkiWiki::urlto", call => \&myurlto);
+ $origsubs{'cgiurl'}=\&IkiWiki::cgiurl;
+ inject(name => "IkiWiki::cgiurl", call => \&mycgiurl);
+}
+
+
+# ,----
+# | Table of contents
+# `----
+
+# 1. Hooks
+# 2. Injected functions
+# 3. Blackboxes for private data
+# 4. Helper functions
+# 5. PageSpecs
+
+
+# ,----
+# | Hooks
+# `----
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0,
+ rebuild => 1,
+ },
+ po_master_language => {
+ type => "string",
+ example => {
+ 'code' => 'en',
+ 'name' => 'English'
+ },
+ description => "master language (non-PO files)",
+ safe => 1,
+ rebuild => 1,
+ },
+ po_slave_languages => {
+ type => "string",
+ example => {
+ 'fr' => 'Français',
+ 'es' => 'Español',
+ 'de' => 'Deutsch'
+ },
+ description => "slave languages (PO files)",
+ safe => 1,
+ rebuild => 1,
+ },
+ po_translatable_pages => {
+ type => "pagespec",
+ example => "* and !*/Discussion",
+ description => "PageSpec controlling which pages are translatable",
+ link => "ikiwiki/PageSpec",
+ safe => 1,
+ rebuild => 1,
+ },
+ po_link_to => {
+ type => "string",
+ example => "current",
+ description => "internal linking behavior (default/current/negotiated)",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig () {
+ foreach my $field (qw{po_master_language}) {
+ if (! exists $config{$field} || ! defined $config{$field}) {
+ error(sprintf(gettext("Must specify %s when using the %s plugin"),
+ $field, 'po'));
+ }
+ }
+
+ map {
+ islanguagecode($_)
+ or error(sprintf(gettext("%s is not a valid language code"), $_));
+ } ($config{po_master_language}{code}, keys %{$config{po_slave_languages}});
+
+ if (! exists $config{po_translatable_pages} ||
+ ! defined $config{po_translatable_pages}) {
+ $config{po_translatable_pages}="";
+ }
+ if (! exists $config{po_link_to} ||
+ ! defined $config{po_link_to}) {
+ $config{po_link_to}='default';
+ }
+ elsif ($config{po_link_to} !~ /^(default|current|negotiated)$/) {
+ warn(sprintf(gettext('%s is not a valid value for po_link_to, falling back to po_link_to=default'),
+ $config{po_link_to}));
+ $config{po_link_to}='default';
+ }
+ elsif ($config{po_link_to} eq "negotiated" && ! $config{usedirs}) {
+ warn(gettext('po_link_to=negotiated requires usedirs to be enabled, falling back to po_link_to=default'));
+ $config{po_link_to}='default';
+ }
+ unless ($config{po_link_to} eq 'default') {
+ $origsubs{'bestlink'}=\&IkiWiki::bestlink;
+ inject(name => "IkiWiki::bestlink", call => \&mybestlink);
+ }
+
+ push @{$config{wiki_file_prune_regexps}}, qr/\.pot$/;
+
+ # Translated versions of the underlays are added if available.
+ foreach my $underlay ("basewiki",
+ map { m/^\Q$config{underlaydirbase}\E\/*(.*)/ }
+ reverse @{$config{underlaydirs}}) {
+ next if $underlay=~/^locale\//;
+
+ # Underlays containing the po files for slave languages.
+ foreach my $ll (keys %{$config{po_slave_languages}}) {
+ add_underlay("po/$ll/$underlay")
+ if -d "$config{underlaydirbase}/po/$ll/$underlay";
+ }
+
+ if ($config{po_master_language}{code} ne 'en') {
+ # Add underlay containing translated source files
+ # for the master language.
+ add_underlay("locale/$config{po_master_language}{code}/$underlay");
+ }
+ }
+}
+
+sub needsbuild () {
+ my $needsbuild=shift;
+
+ # backup @needsbuild content so that change() can know whether
+ # a given master page was rendered because its source file was changed
+ @origneedsbuild=(@$needsbuild);
+
+ flushmemoizecache();
+ buildtranslationscache();
+
+ # make existing translations depend on the corresponding master page
+ foreach my $master (keys %translations) {
+ map add_depends($_, $master), values %{otherlanguages($master)};
+ }
+}
+
+# Massage the recorded state of internal links so that:
+# - it matches the actually generated links, rather than the links as written
+# in the pages' source
+# - backlinks are consistent in all cases
+sub scan (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $content=$params{content};
+
+ if (istranslation($page)) {
+ foreach my $destpage (@{$links{$page}}) {
+ if (istranslatable($destpage)) {
+ # replace the occurence of $destpage in $links{$page}
+ for (my $i=0; $i<@{$links{$page}}; $i++) {
+ if (@{$links{$page}}[$i] eq $destpage) {
+ @{$links{$page}}[$i] = $destpage . '.' . lang($page);
+ last;
+ }
+ }
+ }
+ }
+ }
+ elsif (! istranslatable($page) && ! istranslation($page)) {
+ foreach my $destpage (@{$links{$page}}) {
+ if (istranslatable($destpage)) {
+ # make sure any destpage's translations has
+ # $page in its backlinks
+ push @{$links{$page}},
+ values %{otherlanguages($destpage)};
+ }
+ }
+ }
+}
+
+# We use filter to convert PO to the master page's format,
+# since the rest of ikiwiki should not work on PO files.
+sub filter (@) {
+ my %params = @_;
+
+ my $page = $params{page};
+ my $destpage = $params{destpage};
+ my $content = $params{content};
+ if (istranslation($page) && ! alreadyfiltered($page, $destpage)) {
+ $content = po_to_markup($page, $content);
+ setalreadyfiltered($page, $destpage);
+ }
+ return $content;
+}
+
+sub htmlize (@) {
+ my %params=@_;
+
+ my $page = $params{page};
+ my $content = $params{content};
+
+ # ignore PO files this plugin did not create
+ return $content unless istranslation($page);
+
+ # force content to be htmlize'd as if it was the same type as the master page
+ return IkiWiki::htmlize($page, $page,
+ pagetype(srcfile($pagesources{masterpage($page)})),
+ $content);
+}
+
+sub pagetemplate (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $destpage=$params{destpage};
+ my $template=$params{template};
+
+ my ($masterpage, $lang) = istranslation($page);
+
+ if (istranslation($page) && $template->query(name => "percenttranslated")) {
+ $template->param(percenttranslated => percenttranslated($page));
+ }
+ if ($template->query(name => "istranslation")) {
+ $template->param(istranslation => scalar istranslation($page));
+ }
+ if ($template->query(name => "istranslatable")) {
+ $template->param(istranslatable => istranslatable($page));
+ }
+ if ($template->query(name => "HOMEPAGEURL")) {
+ $template->param(homepageurl => homepageurl($page));
+ }
+ if ($template->query(name => "otherlanguages")) {
+ $template->param(otherlanguages => [otherlanguagesloop($page)]);
+ map add_depends($page, $_), (values %{otherlanguages($page)});
+ }
+ if ($config{discussion} && istranslation($page)) {
+ if ($page !~ /.*\/\Q$config{discussionpage}\E$/i &&
+ (length $config{cgiurl} ||
+ exists $links{$masterpage."/".lc($config{discussionpage})})) {
+ $template->param('discussionlink' => htmllink(
+ $page,
+ $destpage,
+ $masterpage . '/' . $config{discussionpage},
+ noimageinline => 1,
+ forcesubpage => 0,
+ linktext => $config{discussionpage},
+ ));
+ }
+ }
+ # Remove broken parentlink to ./index.html on home page's translations.
+ # It works because this hook has the "last" parameter set, to ensure it
+ # runs after parentlinks' own pagetemplate hook.
+ if ($template->param('parentlinks')
+ && istranslation($page)
+ && $masterpage eq "index") {
+ $template->param('parentlinks' => []);
+ }
+ if (ishomepage($page) && $template->query(name => "title")) {
+ $template->param(title => $config{wikiname});
+ }
+} # }}}
+
+# Add the renamed page translations to the list of to-be-renamed pages.
+sub renamepages (@) {
+ my %params = @_;
+
+ my %torename = %{$params{torename}};
+ my $session = $params{session};
+
+ # Save the page(s) the user asked to rename, so that our
+ # canrename hook can tell the difference between:
+ # - a translation being renamed as a consequence of its master page
+ # being renamed
+ # - a user trying to directly rename a translation
+ # This is why this hook has to be run first, before the list of pages
+ # to rename is modified by other plugins.
+ my @orig_torename;
+ @orig_torename=@{$session->param("po_orig_torename")}
+ if defined $session->param("po_orig_torename");
+ push @orig_torename, $torename{src};
+ $session->param(po_orig_torename => \@orig_torename);
+ IkiWiki::cgi_savesession($session);
+
+ return () unless istranslatable($torename{src});
+
+ my @ret;
+ my %otherpages=%{otherlanguages($torename{src})};
+ while (my ($lang, $otherpage) = each %otherpages) {
+ push @ret, {
+ src => $otherpage,
+ srcfile => $pagesources{$otherpage},
+ dest => otherlanguage($torename{dest}, $lang),
+ destfile => $torename{dest}.".".$lang.".po",
+ required => 0,
+ };
+ }
+ return @ret;
+}
+
+sub mydelete (@) {
+ my @deleted=@_;
+
+ map { deletetranslations($_) } grep istranslatablefile($_), @deleted;
+}
+
+sub change (@) {
+ my @rendered=@_;
+
+ # All meta titles are first extracted at scan time, i.e. before we turn
+ # PO files back into translated markdown; escaping of double-quotes in
+ # PO files breaks the meta plugin's parsing enough to save ugly titles
+ # to %pagestate at this time.
+ #
+ # Then, at render time, every page passes in turn through the Great
+ # Rendering Chain (filter->preprocess->linkify->htmlize), and the meta
+ # plugin's preprocess hook is this time in a position to correctly
+ # extract the titles from slave pages.
+ #
+ # This is, unfortunately, too late: if the page A, linking to the page
+ # B, is rendered before B, it will display the wrongly-extracted meta
+ # title as the link text to B.
+ #
+ # On the one hand, such a corner case only happens on rebuild: on
+ # refresh, every rendered page is fixed to contain correct meta titles.
+ # On the other hand, it can take some time to get every page fixed.
+ # We therefore re-render every rendered page after a rebuild to fix them
+ # at once. As this more or less doubles the time needed to rebuild the
+ # wiki, we do so only when really needed.
+
+ if (@rendered
+ && exists $config{rebuild} && defined $config{rebuild} && $config{rebuild}
+ && UNIVERSAL::can("IkiWiki::Plugin::meta", "getsetup")
+ && exists $config{meta_overrides_page_title}
+ && defined $config{meta_overrides_page_title}
+ && $config{meta_overrides_page_title}) {
+ debug(sprintf(gettext("rebuilding all pages to fix meta titles")));
+ resetalreadyfiltered();
+ require IkiWiki::Render;
+ foreach my $file (@rendered) {
+ debug(sprintf(gettext("building %s"), $file));
+ IkiWiki::render($file);
+ }
+ }
+
+ my $updated_po_files=0;
+
+ # Refresh/create POT and PO files as needed.
+ # (But avoid doing so if they are in an underlay directory.)
+ foreach my $file (grep {istranslatablefile($_)} @rendered) {
+ my $masterfile=srcfile($file);
+ my $page=pagename($file);
+ my $updated_pot_file=0;
+ # Only refresh POT file if it does not exist, or if
+ # $pagesources{$page} was changed: don't if only the HTML was
+ # refreshed, e.g. because of a dependency.
+ if ($masterfile eq "$config{srcdir}/$file" &&
+ ((grep { $_ eq $pagesources{$page} } @origneedsbuild)
+ || ! -e potfile($masterfile))) {
+ refreshpot($masterfile);
+ $updated_pot_file=1;
+ }
+ my @pofiles;
+ foreach my $po (pofiles($masterfile)) {
+ next if ! $updated_pot_file && ! -e $po;
+ next if grep { $po=~/\Q$_\E/ } @{$config{underlaydirs}};
+ push @pofiles, $po;
+ }
+ if (@pofiles) {
+ refreshpofiles($masterfile, @pofiles);
+ map { s/^\Q$config{srcdir}\E\/*//; IkiWiki::rcs_add($_) } @pofiles if $config{rcs};
+ $updated_po_files=1;
+ }
+ }
+
+ if ($updated_po_files) {
+ commit_and_refresh(
+ gettext("updated PO files"),
+ "IkiWiki::Plugin::po::change");
+ }
+}
+
+sub checkcontent (@) {
+ my %params=@_;
+
+ if (istranslation($params{page})) {
+ my $res = isvalidpo($params{content});
+ if ($res) {
+ return undef;
+ }
+ else {
+ return "$res";
+ }
+ }
+ return undef;
+}
+
+sub canremove (@) {
+ my %params = @_;
+
+ if (istranslation($params{page})) {
+ return gettext("Can not remove a translation. If the master page is removed, ".
+ "however, its translations will be removed as well.");
+ }
+ return undef;
+}
+
+sub canrename (@) {
+ my %params = @_;
+ my $session = $params{session};
+
+ if (istranslation($params{src})) {
+ my $masterpage = masterpage($params{src});
+ # Tell the difference between:
+ # - a translation being renamed as a consequence of its master page
+ # being renamed, which is allowed
+ # - a user trying to directly rename a translation, which is forbidden
+ # by looking for the master page in the list of to-be-renamed pages we
+ # saved early in the renaming process.
+ my $orig_torename = $session->param("po_orig_torename");
+ unless (grep { $_ eq $masterpage } @{$orig_torename}) {
+ return gettext("Can not rename a translation. If the master page is renamed, ".
+ "however, its translations will be renamed as well.");
+ }
+ }
+ return undef;
+}
+
+# As we're previewing or saving a page, the content may have
+# changed, so tell the next filter() invocation it must not be lazy.
+sub editcontent () {
+ my %params=@_;
+
+ unsetalreadyfiltered($params{page}, $params{page});
+ return $params{content};
+}
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+ my $form=$params{form};
+ my $q=$params{cgi};
+
+ return unless defined $form->field("do");
+
+ if ($form->field("do") eq "create") {
+ # Warn the user: new pages must be written in master language.
+ my $template=template("pocreatepage.tmpl");
+ $template->param(LANG => $config{po_master_language}{name});
+ $form->tmpl_param(message => $template->output);
+ }
+ elsif ($form->field("do") eq "edit") {
+ # Remove the rename/remove buttons on slave pages.
+ # This has to be done after the rename/remove plugins have added
+ # their buttons, which is why this hook must be run last.
+ # The canrename/canremove hooks already ensure this is forbidden
+ # at the backend level, so this is only UI sugar.
+ if (istranslation($form->field("page"))) {
+ map {
+ for (my $i = 0; $i < @{$params{buttons}}; $i++) {
+ if (@{$params{buttons}}[$i] eq $_) {
+ delete @{$params{buttons}}[$i];
+ last;
+ }
+ }
+ } qw(Rename Remove);
+ }
+ }
+}
+
+sub formbuilder (@) {
+ my %params=@_;
+ my $form=$params{form};
+ my $q=$params{cgi};
+
+ return unless defined $form->field("do");
+
+ # Do not allow to create pages of type po: they are automatically created.
+ # The main reason to do so is to bypass the "favor the type of linking page
+ # on page creation" logic, which is unsuitable when a broken link is clicked
+ # on a slave (PO) page.
+ # This cannot be done in the formbuilder_setup hook as the list of types is
+ # computed later.
+ if ($form->field("do") eq "create") {
+ foreach my $field ($form->field) {
+ next unless "$field" eq "type";
+ if ($field->type eq 'select') {
+ # remove po from the list of types
+ my @types = grep { $_ ne 'po' } $field->options;
+ $field->options(\@types) if @types;
+ }
+ }
+ }
+}
+
+# ,----
+# | Injected functions
+# `----
+
+# Implement po_link_to 'current' and 'negotiated' settings.
+# Not injected otherwise.
+sub mybestlink ($$) {
+ my $page=shift;
+ my $link=shift;
+
+ my $res=$origsubs{'bestlink'}->(masterpage($page), $link);
+ if (length $res
+ && istranslatable($res)
+ && istranslation($page)) {
+ return $res . "." . lang($page);
+ }
+ return $res;
+}
+
+sub mybeautify_urlpath ($) {
+ my $url=shift;
+
+ my $res=$origsubs{'beautify_urlpath'}->($url);
+ if ($config{po_link_to} eq "negotiated") {
+ $res =~ s!/\Qindex.$config{po_master_language}{code}.$config{htmlext}\E$!/!;
+ $res =~ s!/\Qindex.$config{htmlext}\E$!/!;
+ map {
+ $res =~ s!/\Qindex.$_.$config{htmlext}\E$!/!;
+ } (keys %{$config{po_slave_languages}});
+ }
+ return $res;
+}
+
+sub mytargetpage ($$) {
+ my $page=shift;
+ my $ext=shift;
+
+ if (istranslation($page) || istranslatable($page)) {
+ my ($masterpage, $lang) = (masterpage($page), lang($page));
+ if (! $config{usedirs} || $masterpage eq 'index') {
+ return $masterpage . "." . $lang . "." . $ext;
+ }
+ else {
+ return $masterpage . "/index." . $lang . "." . $ext;
+ }
+ }
+ return $origsubs{'targetpage'}->($page, $ext);
+}
+
+sub myurlto ($$;$) {
+ my $to=shift;
+ my $from=shift;
+ my $absolute=shift;
+
+ # workaround hard-coded /index.$config{htmlext} in IkiWiki::urlto()
+ if (! length $to
+ && $config{po_link_to} eq "current"
+ && istranslatable('index')) {
+ return IkiWiki::beautify_urlpath(IkiWiki::baseurl($from) . "index." . lang($from) . ".$config{htmlext}");
+ }
+ # avoid using our injected beautify_urlpath if run by cgi_editpage,
+ # so that one is redirected to the just-edited page rather than to the
+ # negociated translation; to prevent unnecessary fiddling with caller/inject,
+ # we only do so when our beautify_urlpath would actually do what we want to
+ # avoid, i.e. when po_link_to = negotiated.
+ # also avoid doing so when run by cgi_goto, so that the links on recentchanges
+ # page actually lead to the exact page they pretend to.
+ if ($config{po_link_to} eq "negotiated") {
+ my @caller = caller(1);
+ my $use_orig = 0;
+ $use_orig = 1 if (exists $caller[3] && defined $caller[3]
+ && ($caller[3] eq "IkiWiki::cgi_editpage" ||
+ $caller[3] eq "IkiWiki::Plugin::goto::cgi_goto")
+ );
+ inject(name => "IkiWiki::beautify_urlpath", call => $origsubs{'beautify_urlpath'})
+ if $use_orig;
+ my $res = $origsubs{'urlto'}->($to,$from,$absolute);
+ inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath)
+ if $use_orig;
+ return $res;
+ }
+ else {
+ return $origsubs{'urlto'}->($to,$from,$absolute)
+ }
+}
+
+sub mycgiurl (@) {
+ my %params=@_;
+
+ # slave pages have no subpages
+ if (istranslation($params{'from'})) {
+ $params{'from'} = masterpage($params{'from'});
+ }
+ return $origsubs{'cgiurl'}->(%params);
+}
+
+# ,----
+# | Blackboxes for private data
+# `----
+
+{
+ my %filtered;
+
+ sub alreadyfiltered($$) {
+ my $page=shift;
+ my $destpage=shift;
+
+ return exists $filtered{$page}{$destpage}
+ && $filtered{$page}{$destpage} eq 1;
+ }
+
+ sub setalreadyfiltered($$) {
+ my $page=shift;
+ my $destpage=shift;
+
+ $filtered{$page}{$destpage}=1;
+ }
+
+ sub unsetalreadyfiltered($$) {
+ my $page=shift;
+ my $destpage=shift;
+
+ if (exists $filtered{$page}{$destpage}) {
+ delete $filtered{$page}{$destpage};
+ }
+ }
+
+ sub resetalreadyfiltered() {
+ undef %filtered;
+ }
+}
+
+# ,----
+# | Helper functions
+# `----
+
+sub maybe_add_leading_slash ($;$) {
+ my $str=shift;
+ my $add=shift;
+ $add=1 unless defined $add;
+ return '/' . $str if $add;
+ return $str;
+}
+
+sub istranslatablefile ($) {
+ my $file=shift;
+
+ return 0 unless defined $file;
+ my $type=pagetype($file);
+ return 0 if ! defined $type || $type eq 'po';
+ return 0 if $file =~ /\.pot$/;
+ return 1 if pagespec_match(pagename($file), $config{po_translatable_pages});
+ return;
+}
+
+sub istranslatable ($) {
+ my $page=shift;
+
+ $page=~s#^/##;
+ return 1 if istranslatablefile($pagesources{$page});
+ return;
+}
+
+sub _istranslation ($) {
+ my $page=shift;
+
+ $page='' unless defined $page && length $page;
+ my $hasleadingslash = ($page=~s#^/##);
+ my $file=$pagesources{$page};
+ return 0 unless defined $file
+ && defined pagetype($file)
+ && pagetype($file) eq 'po';
+ return 0 if $file =~ /\.pot$/;
+
+ my ($masterpage, $lang) = ($page =~ /(.*)[.]([a-z]{2})$/);
+ return 0 unless defined $masterpage && defined $lang
+ && length $masterpage && length $lang
+ && defined $pagesources{$masterpage}
+ && defined $config{po_slave_languages}{$lang};
+
+ return (maybe_add_leading_slash($masterpage, $hasleadingslash), $lang)
+ if istranslatable($masterpage);
+}
+
+sub istranslation ($) {
+ my $page=shift;
+
+ if (1 < (my ($masterpage, $lang) = _istranslation($page))) {
+ my $hasleadingslash = ($masterpage=~s#^/##);
+ $translations{$masterpage}{$lang}=$page unless exists $translations{$masterpage}{$lang};
+ return (maybe_add_leading_slash($masterpage, $hasleadingslash), $lang);
+ }
+ return "";
+}
+
+sub masterpage ($) {
+ my $page=shift;
+
+ if ( 1 < (my ($masterpage, $lang) = _istranslation($page))) {
+ return $masterpage;
+ }
+ return $page;
+}
+
+sub lang ($) {
+ my $page=shift;
+
+ if (1 < (my ($masterpage, $lang) = _istranslation($page))) {
+ return $lang;
+ }
+ return $config{po_master_language}{code};
+}
+
+sub islanguagecode ($) {
+ my $code=shift;
+
+ return $code =~ /^[a-z]{2}$/;
+}
+
+sub otherlanguage ($$) {
+ my $page=shift;
+ my $code=shift;
+
+ return masterpage($page) if $code eq $config{po_master_language}{code};
+ return masterpage($page) . '.' . $code;
+}
+
+sub otherlanguages ($) {
+ my $page=shift;
+
+ my %ret;
+ return \%ret unless istranslation($page) || istranslatable($page);
+ my $curlang=lang($page);
+ foreach my $lang
+ ($config{po_master_language}{code}, keys %{$config{po_slave_languages}}) {
+ next if $lang eq $curlang;
+ $ret{$lang}=otherlanguage($page, $lang);
+ }
+ return \%ret;
+}
+
+sub potfile ($) {
+ my $masterfile=shift;
+
+ (my $name, my $dir, my $suffix) = fileparse($masterfile, qr/\.[^.]*/);
+ $dir='' if $dir eq './';
+ return File::Spec->catpath('', $dir, $name . ".pot");
+}
+
+sub pofile ($$) {
+ my $masterfile=shift;
+ my $lang=shift;
+
+ (my $name, my $dir, my $suffix) = fileparse($masterfile, qr/\.[^.]*/);
+ $dir='' if $dir eq './';
+ return File::Spec->catpath('', $dir, $name . "." . $lang . ".po");
+}
+
+sub pofiles ($) {
+ my $masterfile=shift;
+
+ return map pofile($masterfile, $_), (keys %{$config{po_slave_languages}});
+}
+
+sub refreshpot ($) {
+ my $masterfile=shift;
+
+ my $potfile=potfile($masterfile);
+ my %options = ("markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0);
+ my $doc=Locale::Po4a::Chooser::new('text',%options);
+ $doc->{TT}{utf_mode} = 1;
+ $doc->{TT}{file_in_charset} = 'utf-8';
+ $doc->{TT}{file_out_charset} = 'utf-8';
+ $doc->read($masterfile);
+ # let's cheat a bit to force porefs option to be passed to
+ # Locale::Po4a::Po; this is undocument use of internal
+ # Locale::Po4a::TransTractor's data, compulsory since this module
+ # prevents us from using the porefs option.
+ $doc->{TT}{po_out}=Locale::Po4a::Po->new({ 'porefs' => 'none' });
+ $doc->{TT}{po_out}->set_charset('utf-8');
+ # do the actual work
+ $doc->parse;
+ IkiWiki::prep_writefile(basename($potfile),dirname($potfile));
+ $doc->writepo($potfile);
+}
+
+sub refreshpofiles ($@) {
+ my $masterfile=shift;
+ my @pofiles=@_;
+
+ my $potfile=potfile($masterfile);
+ if (! -e $potfile) {
+ error("po(refreshpofiles) ".sprintf(gettext("POT file (%s) does not exist"), $potfile));
+ }
+
+ foreach my $pofile (@pofiles) {
+ IkiWiki::prep_writefile(basename($pofile),dirname($pofile));
+
+ if (! -e $pofile) {
+ # If the po file exists in an underlay, copy it
+ # from there.
+ my ($pobase)=$pofile=~/^\Q$config{srcdir}\E\/?(.*)$/;
+ foreach my $dir (@{$config{underlaydirs}}) {
+ if (-e "$dir/$pobase") {
+ File::Copy::syscopy("$dir/$pobase",$pofile)
+ or error("po(refreshpofiles) ".
+ sprintf(gettext("failed to copy underlay PO file to %s"),
+ $pofile));
+ }
+ }
+ }
+
+ if (-e $pofile) {
+ system("msgmerge", "--previous", "-q", "-U", "--backup=none", $pofile, $potfile) == 0
+ or error("po(refreshpofiles) ".
+ sprintf(gettext("failed to update %s"),
+ $pofile));
+ }
+ else {
+ File::Copy::syscopy($potfile,$pofile)
+ or error("po(refreshpofiles) ".
+ sprintf(gettext("failed to copy the POT file to %s"),
+ $pofile));
+ }
+ }
+}
+
+sub buildtranslationscache() {
+ # use istranslation's side-effect
+ map istranslation($_), (keys %pagesources);
+}
+
+sub resettranslationscache() {
+ undef %translations;
+}
+
+sub flushmemoizecache() {
+ Memoize::flush_cache("istranslatable");
+ Memoize::flush_cache("_istranslation");
+ Memoize::flush_cache("percenttranslated");
+}
+
+sub urlto_with_orig_beautiful_urlpath($$) {
+ my $to=shift;
+ my $from=shift;
+
+ inject(name => "IkiWiki::beautify_urlpath", call => $origsubs{'beautify_urlpath'});
+ my $res=urlto($to, $from);
+ inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath);
+
+ return $res;
+}
+
+sub percenttranslated ($) {
+ my $page=shift;
+
+ $page=~s/^\///;
+ return gettext("N/A") unless istranslation($page);
+ my $file=srcfile($pagesources{$page});
+ my $masterfile = srcfile($pagesources{masterpage($page)});
+ my %options = (
+ "markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0,
+ );
+ my $doc=Locale::Po4a::Chooser::new('text',%options);
+ $doc->process(
+ 'po_in_name' => [ $file ],
+ 'file_in_name' => [ $masterfile ],
+ 'file_in_charset' => 'utf-8',
+ 'file_out_charset' => 'utf-8',
+ ) or error("po(percenttranslated) ".
+ sprintf(gettext("failed to translate %s"), $page));
+ my ($percent,$hit,$queries) = $doc->stats();
+ $percent =~ s/\.[0-9]+$//;
+ return $percent;
+}
+
+sub languagename ($) {
+ my $code=shift;
+
+ return $config{po_master_language}{name}
+ if $code eq $config{po_master_language}{code};
+ return $config{po_slave_languages}{$code}
+ if defined $config{po_slave_languages}{$code};
+ return;
+}
+
+sub otherlanguagesloop ($) {
+ my $page=shift;
+
+ my @ret;
+ my %otherpages=%{otherlanguages($page)};
+ while (my ($lang, $otherpage) = each %otherpages) {
+ if (istranslation($page) && masterpage($page) eq $otherpage) {
+ push @ret, {
+ url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
+ code => $lang,
+ language => languagename($lang),
+ master => 1,
+ };
+ }
+ elsif (istranslation($otherpage)) {
+ push @ret, {
+ url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
+ code => $lang,
+ language => languagename($lang),
+ percent => percenttranslated($otherpage),
+ }
+ }
+ }
+ return sort {
+ return -1 if $a->{code} eq $config{po_master_language}{code};
+ return 1 if $b->{code} eq $config{po_master_language}{code};
+ return $a->{language} cmp $b->{language};
+ } @ret;
+}
+
+sub homepageurl (;$) {
+ my $page=shift;
+
+ return urlto('', $page);
+}
+
+sub ishomepage ($) {
+ my $page = shift;
+
+ return 1 if $page eq 'index';
+ map { return 1 if $page eq 'index.'.$_ } keys %{$config{po_slave_languages}};
+ return undef;
+}
+
+sub deletetranslations ($) {
+ my $deletedmasterfile=shift;
+
+ my $deletedmasterpage=pagename($deletedmasterfile);
+ my @todelete;
+ map {
+ my $file = newpagefile($deletedmasterpage.'.'.$_, 'po');
+ my $absfile = "$config{srcdir}/$file";
+ if (-e $absfile && ! -l $absfile && ! -d $absfile) {
+ push @todelete, $file;
+ }
+ } keys %{$config{po_slave_languages}};
+
+ map {
+ if ($config{rcs}) {
+ IkiWiki::rcs_remove($_);
+ }
+ else {
+ IkiWiki::prune("$config{srcdir}/$_");
+ }
+ } @todelete;
+
+ if (@todelete) {
+ commit_and_refresh(
+ gettext("removed obsolete PO files"),
+ "IkiWiki::Plugin::po::deletetranslations");
+ }
+}
+
+sub commit_and_refresh ($$) {
+ my ($msg, $author) = (shift, shift);
+
+ if ($config{rcs}) {
+ IkiWiki::disable_commit_hook();
+ IkiWiki::rcs_commit_staged($msg, $author, "127.0.0.1");
+ IkiWiki::enable_commit_hook();
+ IkiWiki::rcs_update();
+ }
+ # Reinitialize module's private variables.
+ resetalreadyfiltered();
+ resettranslationscache();
+ flushmemoizecache();
+ # Trigger a wiki refresh.
+ require IkiWiki::Render;
+ # without preliminary saveindex/loadindex, refresh()
+ # complains about a lot of uninitialized variables
+ IkiWiki::saveindex();
+ IkiWiki::loadindex();
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+}
+
+# on success, returns the filtered content.
+# on error, if $nonfatal, warn and return undef; else, error out.
+sub po_to_markup ($$;$) {
+ my ($page, $content) = (shift, shift);
+ my $nonfatal = shift;
+
+ $content = '' unless defined $content;
+ $content = decode_utf8(encode_utf8($content));
+ # CRLF line terminators make poor Locale::Po4a feel bad
+ $content=~s/\r\n/\n/g;
+
+ # There are incompatibilities between some File::Temp versions
+ # (including 0.18, bundled with Lenny's perl-modules package)
+ # and others (e.g. 0.20, previously present in the archive as
+ # a standalone package): under certain circumstances, some
+ # return a relative filename, whereas others return an absolute one;
+ # we here use this module in a way that is at least compatible
+ # with 0.18 and 0.20. Beware, hit'n'run refactorers!
+ my $infile = new File::Temp(TEMPLATE => "ikiwiki-po-filter-in.XXXXXXXXXX",
+ DIR => File::Spec->tmpdir,
+ UNLINK => 1)->filename;
+ my $outfile = new File::Temp(TEMPLATE => "ikiwiki-po-filter-out.XXXXXXXXXX",
+ DIR => File::Spec->tmpdir,
+ UNLINK => 1)->filename;
+
+ my $fail = sub ($) {
+ my $msg = "po(po_to_markup) - $page : " . shift;
+ if ($nonfatal) {
+ warn $msg;
+ return undef;
+ }
+ error($msg, sub { unlink $infile, $outfile});
+ };
+
+ writefile(basename($infile), File::Spec->tmpdir, $content)
+ or return $fail->(sprintf(gettext("failed to write %s"), $infile));
+
+ my $masterfile = srcfile($pagesources{masterpage($page)});
+ my %options = (
+ "markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0,
+ );
+ my $doc=Locale::Po4a::Chooser::new('text',%options);
+ $doc->process(
+ 'po_in_name' => [ $infile ],
+ 'file_in_name' => [ $masterfile ],
+ 'file_in_charset' => 'utf-8',
+ 'file_out_charset' => 'utf-8',
+ ) or return $fail->(gettext("failed to translate"));
+ $doc->write($outfile)
+ or return $fail->(sprintf(gettext("failed to write %s"), $outfile));
+
+ $content = readfile($outfile)
+ or return $fail->(sprintf(gettext("failed to read %s"), $outfile));
+
+ # Unlinking should happen automatically, thanks to File::Temp,
+ # but it does not work here, probably because of the way writefile()
+ # and Locale::Po4a::write() work.
+ unlink $infile, $outfile;
+
+ return $content;
+}
+
+# returns a SuccessReason or FailReason object
+sub isvalidpo ($) {
+ my $content = shift;
+
+ # NB: we don't use po_to_markup here, since Po4a parser does
+ # not mind invalid PO content
+ $content = '' unless defined $content;
+ $content = decode_utf8(encode_utf8($content));
+
+ # There are incompatibilities between some File::Temp versions
+ # (including 0.18, bundled with Lenny's perl-modules package)
+ # and others (e.g. 0.20, previously present in the archive as
+ # a standalone package): under certain circumstances, some
+ # return a relative filename, whereas others return an absolute one;
+ # we here use this module in a way that is at least compatible
+ # with 0.18 and 0.20. Beware, hit'n'run refactorers!
+ my $infile = new File::Temp(TEMPLATE => "ikiwiki-po-isvalidpo.XXXXXXXXXX",
+ DIR => File::Spec->tmpdir,
+ UNLINK => 1)->filename;
+
+ my $fail = sub ($) {
+ my $msg = '[po/isvalidpo] ' . shift;
+ unlink $infile;
+ return IkiWiki::FailReason->new("$msg");
+ };
+
+ writefile(basename($infile), File::Spec->tmpdir, $content)
+ or return $fail->(sprintf(gettext("failed to write %s"), $infile));
+
+ my $res = (system("msgfmt", "--check", $infile, "-o", "/dev/null") == 0);
+
+ # Unlinking should happen automatically, thanks to File::Temp,
+ # but it does not work here, probably because of the way writefile()
+ # and Locale::Po4a::write() work.
+ unlink $infile;
+
+ if ($res) {
+ return IkiWiki::SuccessReason->new("valid gettext data");
+ }
+ return IkiWiki::FailReason->new(gettext("invalid gettext data, go back ".
+ "to previous page to continue edit"));
+}
+
+# ,----
+# | PageSpecs
+# `----
+
+package IkiWiki::PageSpec;
+
+sub match_istranslation ($;@) {
+ my $page=shift;
+
+ if (IkiWiki::Plugin::po::istranslation($page)) {
+ return IkiWiki::SuccessReason->new("is a translation page");
+ }
+ else {
+ return IkiWiki::FailReason->new("is not a translation page");
+ }
+}
+
+sub match_istranslatable ($;@) {
+ my $page=shift;
+
+ if (IkiWiki::Plugin::po::istranslatable($page)) {
+ return IkiWiki::SuccessReason->new("is set as translatable in po_translatable_pages");
+ }
+ else {
+ return IkiWiki::FailReason->new("is not set as translatable in po_translatable_pages");
+ }
+}
+
+sub match_lang ($$;@) {
+ my $page=shift;
+ my $wanted=shift;
+
+ my $regexp=IkiWiki::glob2re($wanted);
+ my $lang=IkiWiki::Plugin::po::lang($page);
+ if ($lang !~ /^$regexp$/i) {
+ return IkiWiki::FailReason->new("file language is $lang, not $wanted");
+ }
+ else {
+ return IkiWiki::SuccessReason->new("file language is $wanted");
+ }
+}
+
+sub match_currentlang ($$;@) {
+ my $page=shift;
+ shift;
+ my %params=@_;
+
+ return IkiWiki::FailReason->new("no location provided") unless exists $params{location};
+
+ my $currentlang=IkiWiki::Plugin::po::lang($params{location});
+ my $lang=IkiWiki::Plugin::po::lang($page);
+
+ if ($lang eq $currentlang) {
+ return IkiWiki::SuccessReason->new("file language is the same as current one, i.e. $currentlang");
+ }
+ else {
+ return IkiWiki::FailReason->new("file language is $lang, whereas current language is $currentlang");
+ }
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use Encode;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "poll", call => \&getsetup);
hook(type => "preprocess", id => "poll", call => \&preprocess);
hook(type => "sessioncgi", id => "poll", call => \&sessioncgi);
-} # }}}
+}
-sub yesno ($) { #{{{
- my $val=shift;
- return (defined $val && lc($val) eq "yes");
-} #}}}
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
my %pagenum;
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=(open => "yes", total => "yes", percent => "yes", @_);
- my $open=yesno($params{open});
- my $showtotal=yesno($params{total});
- my $showpercent=yesno($params{percent});
+ my $open=IkiWiki::yesno($params{open});
+ my $showtotal=IkiWiki::yesno($params{total});
+ my $showpercent=IkiWiki::yesno($params{percent});
$pagenum{$params{page}}++;
my %choices;
$ret.="<span>".gettext("Total votes:")." $total</span>\n";
}
return "<div class=poll>$ret</div>";
-} # }}}
+}
-sub sessioncgi ($$) { #{{{
+sub sessioncgi ($$) {
my $cgi=shift;
my $session=shift;
if (defined $cgi->param('do') && $cgi->param('do') eq "poll") {
my $oldchoice=$session->param($choice_param);
if (defined $oldchoice && $oldchoice eq $choice) {
# Same vote; no-op.
- IkiWiki::redirect($cgi, "$config{url}/".htmlpage($page));
+ IkiWiki::redirect($cgi, urlto($page, undef, 1));
exit;
}
error($@) if $@;
my $cookie = CGI::Cookie->new(-name=> $session->name, -value=> $session->id);
print $cgi->redirect(-cookie => $cookie,
- -url => "$config{url}/".htmlpage($page));
+ -url => urlto($page, undef, 1));
exit;
}
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use File::Find;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "polygen", call => \&getsetup);
hook(type => "preprocess", id => "polygen", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
my $grammar = ($params{grammar} or 'polygen');
my $symbol = ($params{symbol} or undef);
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) {
}
if ($?) {
- $res="[[".gettext("polygen failed")."]]";
+ error gettext("command failed");
}
# Strip trailing spaces and newlines so that we flow well with the
# markdown text
$res =~ s/\s*$//;
return $res;
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
IkiWiki::loadplugin('sparkline');
+ hook(type => "getsetup", id => "postsparkline", call => \&getsetup);
hook(type => "preprocess", id => "postsparkline", call => \&preprocess);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
if (! exists $params{max}) {
}
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});
- my @list;
- foreach my $page (keys %pagesources) {
- next if $page eq $params{page};
- if (pagespec_match($page, $params{pages}, location => $params{page})) {
- push @list, $page;
- }
- }
-
- @list = sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } @list;
+ my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} }
+ pagespec_match_list(
+ [ grep { $_ ne $params{page} } keys %pagesources],
+ $params{pages}, location => $params{page});
my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)};
if ($@) {
- return "[[postsparkline error $@]]";
+ error $@;
}
if (! @data) {
delete $params{color};
return IkiWiki::Plugin::sparkline::preprocess(%params,
map { $_.$color => "" } reverse @data);
-} # }}}
+}
sub perfoo ($@) {
my $sub=shift;
#!/usr/bin/perl
package IkiWiki::Plugin::prettydate;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use warnings;
no warnings 'redefine';
use strict;
gettext("%A evening"), # 6
"", # 7
gettext("late %A evening"), # 8
- "", # 9 # 9
+ "", # 9
gettext("%A night"), # 10
"", # 11
];
}
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "prettydate", call => \&getsetup);
hook(type => "checkconfig", id => "prettydate", call => \&checkconfig);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ prettydateformat => {
+ type => "string",
+ example => '%X, %B %o, %Y',
+ description => "format to use to display date",
+ advanced => 1,
+ safe => 1,
+ rebuild => 1,
+ },
+ timetable => {
+ type => "internal",
+ description => "array of time descriptions",
+ safe => 1,
+ rebuild => 1,
+ },
+}
-sub checkconfig () { #{{{
+sub checkconfig () {
if (! defined $config{prettydateformat} ||
$config{prettydateformat} eq '%c') {
$config{prettydateformat}='%X, %B %o, %Y';
$config{timetable}[$h] = $config{timetable}[$h - 1];
}
}
-} #}}}
+}
-sub IkiWiki::displaytime ($;$) { #{{{
+sub IkiWiki::formattime ($;$) {
my $time=shift;
my $format=shift;
if (! defined $format) {
$format=~s/\%X/$t/g;
return strftime($format, \@t);
-} #}}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::progress;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+my $percentage_pattern = qr/[0-9]+\%?/; # pattern to validate percentages
+
+sub import {
+ hook(type => "getsetup", id => "progress", call => \&getsetup);
+ hook(type => "preprocess", id => "progress", call => \&preprocess);
+ hook(type => "format", id => "progress", call => \&format);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
+ my %params=@_;
+
+ my $fill;
+
+ if (defined $params{percent}) {
+ $fill = $params{percent};
+ ($fill) = $fill =~ m/($percentage_pattern)/; # fill is untainted now
+ $fill=~s/%$//;
+ if (! defined $fill || ! length $fill || $fill > 100 || $fill < 0) {
+ error(sprintf(gettext("illegal percent value %s"), $params{percent}));
+ }
+ $fill.="%";
+ }
+ elsif (defined $params{totalpages} and defined $params{donepages}) {
+ add_depends($params{page}, $params{totalpages});
+ add_depends($params{page}, $params{donepages});
+
+ my @pages=keys %pagesources;
+ my $totalcount=0;
+ my $donecount=0;
+ foreach my $page (@pages) {
+ $totalcount++ if pagespec_match($page, $params{totalpages}, location => $params{page});
+ $donecount++ if pagespec_match($page, $params{donepages}, location => $params{page});
+ }
+
+ if ($totalcount == 0) {
+ $fill = "100%";
+ }
+ else {
+ my $number = $donecount/$totalcount*100;
+ $fill = sprintf("%u%%", $number);
+ }
+ }
+ else {
+ error(gettext("need either `percent` or `totalpages` and `donepages` parameters"));
+ }
+
+ return <<EODIV
+<div class="progress">
+ <div class="progress-done" style="width: $fill">$fill</div>
+</div>
+EODIV
+}
+
+sub format(@) {
+ my %params = @_;
+
+ # If HTMLScrubber has removed the style attribute, then bring it back
+
+ $params{content} =~ s!<div class="progress-done">($percentage_pattern)</div>!<div class="progress-done" style="width: $1">$1</div>!g;
+
+ return $params{content};
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "rawhtml", call => \&getsetup);
$config{wiki_file_prune_regexps} = [ grep { !m/\\\.x\?html\?\$/ } @{$config{wiki_file_prune_regexps}} ];
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # changes file types
+ },
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
+use Encode;
+use HTML::Entities;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "recentchanges", call => \&getsetup);
hook(type => "checkconfig", id => "recentchanges", call => \&checkconfig);
hook(type => "refresh", id => "recentchanges", call => \&refresh);
hook(type => "pagetemplate", id => "recentchanges", call => \&pagetemplate);
hook(type => "htmlize", id => "_change", call => \&htmlize);
- hook(type => "cgi", id => "recentchanges", call => \&cgi);
-} #}}}
+ # Load goto to fix up links from recentchanges
+ IkiWiki::loadplugin("goto");
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ recentchangespage => {
+ type => "string",
+ example => "recentchanges",
+ description => "name of the recentchanges page",
+ safe => 1,
+ rebuild => 1,
+ },
+ recentchangesnum => {
+ type => "integer",
+ example => 100,
+ description => "number of changes to track",
+ safe => 1,
+ rebuild => 0,
+ },
+}
-sub checkconfig () { #{{{
+sub checkconfig () {
$config{recentchangespage}='recentchanges' unless defined $config{recentchangespage};
$config{recentchangesnum}=100 unless defined $config{recentchangesnum};
-} #}}}
+}
-sub refresh ($) { #{{{
+sub refresh ($) {
my %seen;
# add new changes
unlink($config{srcdir}.'/'.$pagesources{$page});
}
}
-} #}}}
+}
# Enable the recentchanges link on wiki pages.
-sub pagetemplate (@) { #{{{
+sub pagetemplate (@) {
my %params=@_;
my $template=$params{template};
my $page=$params{page};
$template->param(recentchangesurl => urlto($config{recentchangespage}, $page));
$template->param(have_actions => 1);
}
-} #}}}
+}
# Pages with extension _change have plain html markup, pass through.
-sub htmlize (@) { #{{{
+sub htmlize (@) {
my %params=@_;
return $params{content};
-} #}}}
-
-sub cgi ($) { #{{{
- my $cgi=shift;
- if (defined $cgi->param('do') && $cgi->param('do') eq "recentchanges_link") {
- # This is a link from a change page to some
- # other page. Since the change pages are only generated
- # once, statically, links on them won't be updated if the
- # page they link to is deleted, or newly created, or
- # changes for whatever reason. So this CGI handles that
- # dynamic linking stuff.
- my $page=$cgi->param("page");
- if (!defined $page) {
- error("missing page parameter");
- }
-
- IkiWiki::loadindex();
-
- my $link=bestlink("", $page);
- if (! length $link) {
- print "Content-type: text/html\n\n";
- print IkiWiki::misctemplate(gettext(gettext("missing page")),
- "<p>".
- sprintf(gettext("The page %s does not exist."),
- htmllink("", "", $page)).
- "</p>");
- }
- else {
- IkiWiki::redirect($cgi, $config{url}."/".htmlpage($link));
- }
-
- exit;
- }
}
-sub store ($$$) { #{{{
+sub store ($$$) {
my $change=shift;
- my $page="$config{recentchangespage}/change_".IkiWiki::titlepage($change->{rev});
+ my $page="$config{recentchangespage}/change_".titlepage($change->{rev});
# Optimisation to avoid re-writing pages. Assumes commits never
# change (or that any changes are not important).
if (length $config{cgiurl}) {
$_->{link} = "<a href=\"".
IkiWiki::cgiurl(
- do => "recentchanges_link",
+ do => "goto",
page => $_->{page}
).
- "\">".
- IkiWiki::pagetitle($_->{page}).
+ "\" rel=\"nofollow\">".
+ pagetitle($_->{page}).
"</a>"
}
else {
- $_->{link} = IkiWiki::pagetitle($_->{page});
+ $_->{link} = pagetitle($_->{page});
}
$_->{baseurl}="$config{url}/" if length $config{url};
}
elsif (length $config{cgiurl}) {
$change->{authorurl} = IkiWiki::cgiurl(
- do => "recentchanges_link",
+ do => "goto",
page => (length $config{userdir} ? "$config{userdir}/" : "").$change->{author},
);
}
- # escape wikilinks and preprocessor stuff in commit messages
if (ref $change->{message}) {
foreach my $field (@{$change->{message}}) {
if (exists $field->{line}) {
- $field->{line} =~ s/(?<!\\)\[\[/\\\[\[/g;
+ # escape html
+ $field->{line} = encode_entities($field->{line});
+ # escape links and preprocessor stuff
+ $field->{line} = encode_entities($field->{line}, '\[\]');
}
}
}
commitdate => displaytime($change->{when}, "%X %x"),
wikiname => $config{wikiname},
);
+
+ $template->param(permalink => "$config{url}/$config{recentchangespage}/#change-".titlepage($change->{rev}))
+ if exists $config{url};
+
IkiWiki::run_hooks(pagetemplate => sub {
shift->(page => $page, destpage => $page,
template => $template, rev => $change->{rev});
utime $change->{when}, $change->{when}, "$config{srcdir}/$file";
return $page;
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
+use HTML::Entities;
my $maxlines=200;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "recentchangesdiff",
+ call => \&getsetup);
hook(type => "pagetemplate", id => "recentchangesdiff",
call => \&pagetemplate);
-} #}}}
+}
-sub pagetemplate (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub pagetemplate (@) {
my %params=@_;
my $template=$params{template};
if ($config{rcs} && exists $params{rev} && length $params{rev} &&
else {
$diff=join("", @lines);
}
+ # escape html
+ $diff = encode_entities($diff);
# escape links and preprocessor stuff
- $diff =~ s/(?<!\\)\[\[/\\\[\[/g;
+ $diff = encode_entities($diff, '\[\]');
$template->param(diff => $diff);
}
}
-} #}}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::relativedate;
+
+use warnings;
+no warnings 'redefine';
+use strict;
+use IkiWiki 3.00;
+use POSIX;
+use Encode;
+
+sub import {
+ add_underlay("javascript");
+ hook(type => "getsetup", id => "relativedate", call => \&getsetup);
+ hook(type => "format", id => "relativedate", call => \&format);
+ inject(name => "IkiWiki::displaytime", call => \&mydisplaytime);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub format (@) {
+ my %params=@_;
+
+ if (! ($params{content}=~s!^(<body>)!$1.include_javascript($params{page})!em)) {
+ # no </body> tag, probably in preview mode
+ $params{content}=include_javascript($params{page}, 1).$params{content};
+ }
+ return $params{content};
+}
+
+sub include_javascript ($;$) {
+ my $page=shift;
+ my $absolute=shift;
+
+ return '<script src="'.urlto("ikiwiki.js", $page, $absolute).
+ '" type="text/javascript" charset="utf-8"></script>'."\n".
+ '<script src="'.urlto("relativedate.js", $page, $absolute).
+ '" type="text/javascript" charset="utf-8"></script>';
+}
+
+sub mydisplaytime ($;$) {
+ my $time=shift;
+ my $format=shift;
+
+ # This needs to be in a form that can be parsed by javascript.
+ # Being fairly human readable is also nice, as it will be exposed
+ # as the title if javascript is not available.
+ my $gmtime=decode_utf8(POSIX::strftime("%a, %d %b %Y %H:%M:%S %z",
+ localtime($time)));
+
+ return '<span class="relativedate" title="'.$gmtime.'">'.
+ IkiWiki::formattime($time, $format).'</span>';
+}
+
+1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::remove;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getsetup", id => "remove", call => \&getsetup);
+ hook(type => "formbuilder_setup", id => "remove", call => \&formbuilder_setup);
+ hook(type => "formbuilder", id => "remove", call => \&formbuilder);
+ hook(type => "sessioncgi", id => "remove", call => \&sessioncgi);
+
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub check_canremove ($$$) {
+ my $page=shift;
+ my $q=shift;
+ my $session=shift;
+
+ # Must be a known source file.
+ if (! exists $pagesources{$page}) {
+ error(sprintf(gettext("%s does not exist"),
+ htmllink("", "", $page, noimageinline => 1)));
+ }
+
+ # Must exist on disk, and be a regular file.
+ my $file=$pagesources{$page};
+ if (! -e "$config{srcdir}/$file") {
+ error(sprintf(gettext("%s is not in the srcdir, so it cannot be deleted"), $file));
+ }
+ elsif (-l "$config{srcdir}/$file" && ! -f _) {
+ error(sprintf(gettext("%s is not a file"), $file));
+ }
+
+ # Must be editable.
+ IkiWiki::check_canedit($page, $q, $session);
+
+ # If a user can't upload an attachment, don't let them delete it.
+ # This is sorta overkill, but better safe than sorry.
+ if (! defined pagetype($pagesources{$page})) {
+ if (IkiWiki::Plugin::attachment->can("check_canattach")) {
+ IkiWiki::Plugin::attachment::check_canattach($session, $page, $file);
+ }
+ else {
+ error("renaming of attachments is not allowed");
+ }
+ }
+
+ my $canremove;
+ IkiWiki::run_hooks(canremove => sub {
+ return if defined $canremove;
+ my $ret=shift->(page => $page, cgi => $q, session => $session);
+ if (defined $ret) {
+ if ($ret eq "") {
+ $canremove=1;
+ }
+ elsif (ref $ret eq 'CODE') {
+ $ret->();
+ $canremove=0;
+ }
+ elsif (defined $ret) {
+ error($ret);
+ $canremove=0;
+ }
+ }
+ });
+}
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+ my $form=$params{form};
+ my $q=$params{cgi};
+
+ if (defined $form->field("do") && ($form->field("do") eq "edit" ||
+ $form->field("do") eq "create")) {
+ # Removal button for the page, and also for attachments.
+ push @{$params{buttons}}, "Remove" if $form->field("do") eq "edit";
+ $form->tmpl_param("field-remove" => '<input name="_submit" type="submit" value="Remove Attachments" />');
+ }
+}
+
+sub confirmation_form ($$) {
+ my $q=shift;
+ my $session=shift;
+
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+ my $f = CGI::FormBuilder->new(
+ name => "remove",
+ header => 0,
+ charset => "utf-8",
+ method => 'POST',
+ javascript => 0,
+ params => $q,
+ action => $config{cgiurl},
+ stylesheet => IkiWiki::baseurl()."style.css",
+ fields => [qw{do page}],
+ );
+
+ $f->field(name => "do", type => "hidden", value => "remove", force => 1);
+
+ return $f, ["Remove", "Cancel"];
+}
+
+sub removal_confirm ($$@) {
+ my $q=shift;
+ my $session=shift;
+ my $attachment=shift;
+ my @pages=@_;
+
+ foreach my $page (@pages) {
+ check_canremove($page, $q, $session);
+ }
+
+ # Save current form state to allow returning to it later
+ # without losing any edits.
+ # (But don't save what button was submitted, to avoid
+ # looping back to here.)
+ # Note: "_submit" is CGI::FormBuilder internals.
+ $q->param(-name => "_submit", -value => "");
+ $session->param(postremove => scalar $q->Vars);
+ IkiWiki::cgi_savesession($session);
+
+ my ($f, $buttons)=confirmation_form($q, $session);
+ $f->title(sprintf(gettext("confirm removal of %s"),
+ join(", ", map { pagetitle($_) } @pages)));
+ $f->field(name => "page", type => "hidden", value => \@pages, force => 1);
+ if (defined $attachment) {
+ $f->field(name => "attachment", type => "hidden",
+ value => $attachment, force => 1);
+ }
+
+ IkiWiki::showform($f, $buttons, $session, $q);
+ exit 0;
+}
+
+sub postremove ($) {
+ my $session=shift;
+
+ # Load saved form state and return to edit form.
+ my $postremove=CGI->new($session->param("postremove"));
+ $session->clear("postremove");
+ IkiWiki::cgi_savesession($session);
+ IkiWiki::cgi($postremove, $session);
+}
+
+sub formbuilder (@) {
+ my %params=@_;
+ my $form=$params{form};
+
+ if (defined $form->field("do") && ($form->field("do") eq "edit" ||
+ $form->field("do") eq "create")) {
+ my $q=$params{cgi};
+ my $session=$params{session};
+
+ if ($form->submitted eq "Remove" && $form->field("do") eq "edit") {
+ removal_confirm($q, $session, 0, $form->field("page"));
+ }
+ elsif ($form->submitted eq "Remove Attachments") {
+ my @selected=$q->param("attachment_select");
+ if (! @selected) {
+ error(gettext("Please select the attachments to remove."));
+ }
+ removal_confirm($q, $session, 1, @selected);
+ }
+ }
+}
+
+sub sessioncgi ($$) {
+ my $q=shift;
+
+ if ($q->param("do") eq 'remove') {
+ my $session=shift;
+ my ($form, $buttons)=confirmation_form($q, $session);
+ IkiWiki::decode_form_utf8($form);
+
+ if ($form->submitted eq 'Cancel') {
+ postremove($session);
+ }
+ elsif ($form->submitted eq 'Remove' && $form->validate) {
+ my @pages=$q->param("page");
+
+ # Validate removal by checking that the page exists,
+ # and that the user is allowed to edit(/remove) it.
+ my @files;
+ foreach my $page (@pages) {
+ check_canremove($page, $q, $session);
+
+ # This untaint is safe because of the
+ # checks performed above, which verify the
+ # page is a normal file, etc.
+ push @files, IkiWiki::possibly_foolish_untaint($pagesources{$page});
+ }
+
+ # Do removal, and update the wiki.
+ require IkiWiki::Render;
+ if ($config{rcs}) {
+ IkiWiki::disable_commit_hook();
+ foreach my $file (@files) {
+ IkiWiki::rcs_remove($file);
+ }
+ IkiWiki::rcs_commit_staged(gettext("removed"),
+ $session->param("name"), $ENV{REMOTE_ADDR});
+ IkiWiki::enable_commit_hook();
+ IkiWiki::rcs_update();
+ }
+ else {
+ foreach my $file (@files) {
+ IkiWiki::prune("$config{srcdir}/$file");
+ }
+ }
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+
+ if ($q->param("attachment")) {
+ # Attachments were deleted, so redirect
+ # back to the edit form.
+ postremove($session);
+ }
+ else {
+ # The page is gone, so redirect to parent
+ # of the page.
+ my $parent=IkiWiki::dirname($pages[0]);
+ if (! exists $pagesources{$parent}) {
+ $parent="index";
+ }
+ IkiWiki::redirect($q, urlto($parent, '/', 1));
+ }
+ }
+ else {
+ removal_confirm($q, $session, 0, $q->param("page"));
+ }
+
+ exit 0;
+ }
+}
+
+1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::rename;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getsetup", id => "rename", call => \&getsetup);
+ hook(type => "formbuilder_setup", id => "rename", call => \&formbuilder_setup);
+ hook(type => "formbuilder", id => "rename", call => \&formbuilder);
+ hook(type => "sessioncgi", id => "rename", call => \&sessioncgi);
+ hook(type => "rename", id => "rename", call => \&rename_subpages);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub check_canrename ($$$$$$) {
+ my $src=shift;
+ my $srcfile=shift;
+ my $dest=shift;
+ my $destfile=shift;
+ my $q=shift;
+ my $session=shift;
+
+ my $attachment=! defined pagetype($pagesources{$src});
+
+ # Must be a known source file.
+ if (! exists $pagesources{$src}) {
+ error(sprintf(gettext("%s does not exist"),
+ htmllink("", "", $src, noimageinline => 1)));
+ }
+
+ # Must exist on disk, and be a regular file.
+ if (! -e "$config{srcdir}/$srcfile") {
+ error(sprintf(gettext("%s is not in the srcdir, so it cannot be renamed"), $srcfile));
+ }
+ elsif (-l "$config{srcdir}/$srcfile" && ! -f _) {
+ error(sprintf(gettext("%s is not a file"), $srcfile));
+ }
+
+ # Must be editable.
+ IkiWiki::check_canedit($src, $q, $session);
+ if ($attachment) {
+ if (IkiWiki::Plugin::attachment->can("check_canattach")) {
+ IkiWiki::Plugin::attachment::check_canattach($session, $src, $srcfile);
+ }
+ else {
+ error("renaming of attachments is not allowed");
+ }
+ }
+
+ # Dest checks can be omitted by passing undef.
+ if (defined $dest) {
+ if ($srcfile eq $destfile) {
+ error(gettext("no change to the file name was specified"));
+ }
+
+ # Must be a legal filename, and not absolute.
+ if (IkiWiki::file_pruned($destfile, $config{srcdir}) ||
+ $destfile=~/^\//) {
+ error(sprintf(gettext("illegal name")));
+ }
+
+ # Must not be a known source file.
+ if ($src ne $dest && exists $pagesources{$dest}) {
+ error(sprintf(gettext("%s already exists"),
+ htmllink("", "", $dest, noimageinline => 1)));
+ }
+
+ # Must not exist on disk already.
+ if (-l "$config{srcdir}/$destfile" || -e _) {
+ error(sprintf(gettext("%s already exists on disk"), $destfile));
+ }
+
+ # Must be editable.
+ IkiWiki::check_canedit($dest, $q, $session);
+ if ($attachment) {
+ # Note that $srcfile is used here, not $destfile,
+ # because it wants the current file, to check it.
+ IkiWiki::Plugin::attachment::check_canattach($session, $dest, $srcfile);
+ }
+ }
+
+ my $canrename;
+ IkiWiki::run_hooks(canrename => sub {
+ return if defined $canrename;
+ my $ret=shift->(cgi => $q, session => $session,
+ src => $src, srcfile => $srcfile,
+ dest => $dest, destfile => $destfile);
+ if (defined $ret) {
+ if ($ret eq "") {
+ $canrename=1;
+ }
+ elsif (ref $ret eq 'CODE') {
+ $ret->();
+ $canrename=0;
+ }
+ elsif (defined $ret) {
+ error($ret);
+ $canrename=0;
+ }
+ }
+ });
+}
+
+sub rename_form ($$$) {
+ my $q=shift;
+ my $session=shift;
+ my $page=shift;
+
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+ my $f = CGI::FormBuilder->new(
+ name => "rename",
+ title => sprintf(gettext("rename %s"), pagetitle($page)),
+ header => 0,
+ charset => "utf-8",
+ method => 'POST',
+ javascript => 0,
+ params => $q,
+ action => $config{cgiurl},
+ stylesheet => IkiWiki::baseurl()."style.css",
+ fields => [qw{do page new_name attachment}],
+ );
+
+ $f->field(name => "do", type => "hidden", value => "rename", force => 1);
+ $f->field(name => "page", type => "hidden", value => $page, force => 1);
+ $f->field(name => "new_name", value => pagetitle($page, 1), size => 60);
+ if (!$q->param("attachment")) {
+ # insert the standard extensions
+ my @page_types;
+ if (exists $IkiWiki::hooks{htmlize}) {
+ foreach my $key (grep { !/^_/ } keys %{$IkiWiki::hooks{htmlize}}) {
+ push @page_types, [$key, $IkiWiki::hooks{htmlize}{$key}{longname} || $key];
+ }
+ }
+ @page_types=sort @page_types;
+
+ # make sure the current extension is in the list
+ my ($ext) = $pagesources{$page}=~/\.([^.]+)$/;
+ if (! $IkiWiki::hooks{htmlize}{$ext}) {
+ unshift(@page_types, [$ext, $ext]);
+ }
+
+ $f->field(name => "type", type => 'select',
+ options => \@page_types,
+ value => $ext, force => 1);
+
+ foreach my $p (keys %pagesources) {
+ if ($pagesources{$p}=~m/^\Q$page\E\//) {
+ $f->field(name => "subpages",
+ label => "",
+ type => "checkbox",
+ options => [ [ 1 => gettext("Also rename SubPages and attachments") ] ],
+ value => 1,
+ force => 1);
+ last;
+ }
+ }
+ }
+ $f->field(name => "attachment", type => "hidden");
+
+ return $f, ["Rename", "Cancel"];
+}
+
+sub rename_start ($$$$) {
+ my $q=shift;
+ my $session=shift;
+ my $attachment=shift;
+ my $page=shift;
+
+ check_canrename($page, $pagesources{$page}, undef, undef,
+ $q, $session);
+
+ # Save current form state to allow returning to it later
+ # without losing any edits.
+ # (But don't save what button was submitted, to avoid
+ # looping back to here.)
+ # Note: "_submit" is CGI::FormBuilder internals.
+ $q->param(-name => "_submit", -value => "");
+ $session->param(postrename => scalar $q->Vars);
+ IkiWiki::cgi_savesession($session);
+
+ if (defined $attachment) {
+ $q->param(-name => "attachment", -value => $attachment);
+ }
+ my ($f, $buttons)=rename_form($q, $session, $page);
+ IkiWiki::showform($f, $buttons, $session, $q);
+ exit 0;
+}
+
+sub postrename ($;$$$) {
+ my $session=shift;
+ my $src=shift;
+ my $dest=shift;
+ my $attachment=shift;
+
+ # Load saved form state and return to edit page.
+ my $postrename=CGI->new($session->param("postrename"));
+ $session->clear("postrename");
+ IkiWiki::cgi_savesession($session);
+
+ if (defined $dest) {
+ if (! $attachment) {
+ # They renamed the page they were editing. This requires
+ # fixups to the edit form state.
+ # Tweak the edit form to be editing the new page.
+ $postrename->param("page", $dest);
+ }
+
+ # Update edit form content to fix any links present
+ # on it.
+ $postrename->param("editcontent",
+ renamepage_hook($dest, $src, $dest,
+ $postrename->param("editcontent")));
+
+ # Get a new edit token; old was likely invalidated.
+ $postrename->param("rcsinfo",
+ IkiWiki::rcs_prepedit($pagesources{$dest}));
+ }
+
+ IkiWiki::cgi_editpage($postrename, $session);
+}
+
+sub formbuilder (@) {
+ my %params=@_;
+ my $form=$params{form};
+
+ if (defined $form->field("do") && ($form->field("do") eq "edit" ||
+ $form->field("do") eq "create")) {
+ my $q=$params{cgi};
+ my $session=$params{session};
+
+ if ($form->submitted eq "Rename" && $form->field("do") eq "edit") {
+ rename_start($q, $session, 0, $form->field("page"));
+ }
+ elsif ($form->submitted eq "Rename Attachment") {
+ my @selected=$q->param("attachment_select");
+ if (@selected > 1) {
+ error(gettext("Only one attachment can be renamed at a time."));
+ }
+ elsif (! @selected) {
+ error(gettext("Please select the attachment to rename."))
+ }
+ rename_start($q, $session, 1, $selected[0]);
+ }
+ }
+}
+
+my $renamesummary;
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+ my $form=$params{form};
+ my $q=$params{cgi};
+
+ if (defined $form->field("do") && ($form->field("do") eq "edit" ||
+ $form->field("do") eq "create")) {
+ # Rename button for the page, and also for attachments.
+ push @{$params{buttons}}, "Rename" if $form->field("do") eq "edit";
+ $form->tmpl_param("field-rename" => '<input name="_submit" type="submit" value="Rename Attachment" />');
+
+ if (defined $renamesummary) {
+ $form->tmpl_param(message => $renamesummary);
+ }
+ }
+}
+
+sub sessioncgi ($$) {
+ my $q=shift;
+
+ if ($q->param("do") eq 'rename') {
+ my $session=shift;
+ my ($form, $buttons)=rename_form($q, $session, $q->param("page"));
+ IkiWiki::decode_form_utf8($form);
+
+ if ($form->submitted eq 'Cancel') {
+ postrename($session);
+ }
+ elsif ($form->submitted eq 'Rename' && $form->validate) {
+ # Queue of rename actions to perfom.
+ my @torename;
+
+ # These untaints are safe because of the checks
+ # performed in check_canrename later.
+ my $src=$q->param("page");
+ my $srcfile=IkiWiki::possibly_foolish_untaint($pagesources{$src});
+ my $dest=IkiWiki::possibly_foolish_untaint(titlepage($q->param("new_name")));
+ my $destfile=$dest;
+ if (! $q->param("attachment")) {
+ my $type=$q->param('type');
+ if (defined $type && length $type && $IkiWiki::hooks{htmlize}{$type}) {
+ $type=IkiWiki::possibly_foolish_untaint($type);
+ }
+ else {
+ my ($ext)=$srcfile=~/\.([^.]+)$/;
+ $type=$ext;
+ }
+
+ $destfile=newpagefile($dest, $type);
+ }
+ push @torename, {
+ src => $src,
+ srcfile => $srcfile,
+ dest => $dest,
+ destfile => $destfile,
+ required => 1,
+ };
+
+ @torename=rename_hook(
+ torename => \@torename,
+ done => {},
+ cgi => $q,
+ session => $session,
+ );
+
+ require IkiWiki::Render;
+ IkiWiki::disable_commit_hook() if $config{rcs};
+ my %origpagesources=%pagesources;
+
+ # First file renaming.
+ foreach my $rename (@torename) {
+ if ($rename->{required}) {
+ do_rename($rename, $q, $session);
+ }
+ else {
+ eval {do_rename($rename, $q, $session)};
+ if ($@) {
+ $rename->{error}=$@;
+ next;
+ }
+ }
+
+ # Temporarily tweak pagesources to point to
+ # the renamed file, in case fixlinks needs
+ # to edit it.
+ $pagesources{$rename->{src}}=$rename->{destfile};
+ }
+ IkiWiki::rcs_commit_staged(
+ sprintf(gettext("rename %s to %s"), $srcfile, $destfile),
+ $session->param("name"), $ENV{REMOTE_ADDR}) if $config{rcs};
+
+ # Then link fixups.
+ foreach my $rename (@torename) {
+ next if $rename->{src} eq $rename->{dest};
+ next if $rename->{error};
+ foreach my $p (fixlinks($rename, $session)) {
+ # map old page names to new
+ foreach my $r (@torename) {
+ next if $rename->{error};
+ if ($r->{src} eq $p) {
+ $p=$r->{dest};
+ last;
+ }
+ }
+ push @{$rename->{fixedlinks}}, $p;
+ }
+ }
+
+ # Then refresh.
+ %pagesources=%origpagesources;
+ if ($config{rcs}) {
+ IkiWiki::enable_commit_hook();
+ IkiWiki::rcs_update();
+ }
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+
+ # Find pages with remaining, broken links.
+ foreach my $rename (@torename) {
+ next if $rename->{src} eq $rename->{dest};
+
+ foreach my $page (keys %links) {
+ my $broken=0;
+ foreach my $link (@{$links{$page}}) {
+ my $bestlink=bestlink($page, $link);
+ if ($bestlink eq $rename->{src}) {
+ push @{$rename->{brokenlinks}}, $page;
+ last;
+ }
+ }
+ }
+ }
+
+ # Generate a summary, that will be shown at the top
+ # of the edit template.
+ $renamesummary="";
+ foreach my $rename (@torename) {
+ my $template=template("renamesummary.tmpl");
+ $template->param(src => $rename->{srcfile});
+ $template->param(dest => $rename->{destfile});
+ $template->param(error => $rename->{error});
+ if ($rename->{src} ne $rename->{dest}) {
+ $template->param(brokenlinks_checked => 1);
+ $template->param(brokenlinks => linklist($rename->{dest}, $rename->{brokenlinks}));
+ $template->param(fixedlinks => linklist($rename->{dest}, $rename->{fixedlinks}));
+ }
+ $renamesummary.=$template->output;
+ }
+
+ postrename($session, $src, $dest, $q->param("attachment"));
+ }
+ else {
+ IkiWiki::showform($form, $buttons, $session, $q);
+ }
+
+ exit 0;
+ }
+}
+
+# Add subpages to the list of pages to be renamed, if needed.
+sub rename_subpages (@) {
+ my %params = @_;
+
+ my %torename = %{$params{torename}};
+ my $q = $params{cgi};
+ my $src = $torename{src};
+ my $srcfile = $torename{src};
+ my $dest = $torename{dest};
+ my $destfile = $torename{dest};
+
+ return () unless ($q->param("subpages") && $src ne $dest);
+
+ my @ret;
+ foreach my $p (keys %pagesources) {
+ next unless $pagesources{$p}=~m/^\Q$src\E\//;
+ # If indexpages is enabled, the srcfile should not be confused
+ # with a subpage.
+ next if $pagesources{$p} eq $srcfile;
+
+ my $d=$pagesources{$p};
+ $d=~s/^\Q$src\E\//$dest\//;
+ push @ret, {
+ src => $p,
+ srcfile => $pagesources{$p},
+ dest => pagename($d),
+ destfile => $d,
+ required => 0,
+ };
+ }
+ return @ret;
+}
+
+sub linklist {
+ # generates a list of links in a form suitable for FormBuilder
+ my $dest=shift;
+ my $list=shift;
+ # converts a list of pages into a list of links
+ # in a form suitable for FormBuilder.
+
+ [map {
+ {
+ page => htmllink($dest, $dest, $_,
+ noimageinline => 1,
+ linktext => pagetitle($_),
+ )
+ }
+ } @{$list}]
+}
+
+sub renamepage_hook ($$$$) {
+ my ($page, $src, $dest, $content)=@_;
+
+ IkiWiki::run_hooks(renamepage => sub {
+ $content=shift->(
+ page => $page,
+ oldpage => $src,
+ newpage => $dest,
+ content => $content,
+ );
+ });
+
+ return $content;
+}
+
+sub rename_hook {
+ my %params = @_;
+
+ my @torename=@{$params{torename}};
+ my %done=%{$params{done}};
+ my $q=$params{cgi};
+ my $session=$params{session};
+
+ return () unless @torename;
+
+ my @nextset;
+ foreach my $torename (@torename) {
+ unless (exists $done{$torename->{src}} && $done{$torename->{src}}) {
+ IkiWiki::run_hooks(rename => sub {
+ push @nextset, shift->(
+ torename => $torename,
+ cgi => $q,
+ session => $session,
+ );
+ });
+ $done{$torename->{src}}=1;
+ }
+ }
+
+ push @torename, rename_hook(
+ torename => \@nextset,
+ done => \%done,
+ cgi => $q,
+ session => $session,
+ );
+
+ # dedup
+ my %seen;
+ return grep { ! $seen{$_->{src}}++ } @torename;
+}
+
+sub do_rename ($$$) {
+ my $rename=shift;
+ my $q=shift;
+ my $session=shift;
+
+ # First, check if this rename is allowed.
+ check_canrename($rename->{src},
+ $rename->{srcfile},
+ $rename->{dest},
+ $rename->{destfile},
+ $q, $session);
+
+ # Ensure that the dest directory exists and is ok.
+ IkiWiki::prep_writefile($rename->{destfile}, $config{srcdir});
+
+ if ($config{rcs}) {
+ IkiWiki::rcs_rename($rename->{srcfile}, $rename->{destfile});
+ }
+ else {
+ if (! rename($config{srcdir}."/".$rename->{srcfile},
+ $config{srcdir}."/".$rename->{destfile})) {
+ error("rename: $!");
+ }
+ }
+
+}
+
+sub fixlinks ($$$) {
+ my $rename=shift;
+ my $session=shift;
+
+ my @fixedlinks;
+
+ foreach my $page (keys %links) {
+ my $needfix=0;
+ foreach my $link (@{$links{$page}}) {
+ my $bestlink=bestlink($page, $link);
+ if ($bestlink eq $rename->{src}) {
+ $needfix=1;
+ last;
+ }
+ }
+ if ($needfix) {
+ my $file=$pagesources{$page};
+ my $oldcontent=readfile($config{srcdir}."/".$file);
+ my $content=renamepage_hook($page, $rename->{src}, $rename->{dest}, $oldcontent);
+ if ($oldcontent ne $content) {
+ my $token=IkiWiki::rcs_prepedit($file);
+ eval { writefile($file, $config{srcdir}, $content) };
+ next if $@;
+ my $conflict=IkiWiki::rcs_commit(
+ $file,
+ sprintf(gettext("update for rename of %s to %s"), $rename->{srcfile}, $rename->{destfile}),
+ $token,
+ $session->param("name"),
+ $ENV{REMOTE_ADDR}
+ );
+ push @fixedlinks, $page if ! defined $conflict;
+ }
+ }
+ }
+
+ return @fixedlinks;
+}
+
+1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::repolist;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getsetup", id => "repolist", call => \&getsetup);
+ hook(type => "checkconfig", id => "repolist", call => \&checkconfig);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ repositories => {
+ type => "string",
+ example => ["svn://svn.example.org/wiki/trunk"],
+ description => "URIs of repositories containing the wiki's source",
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+my $relvcs;
+
+sub checkconfig () {
+ if (defined $config{rcs} && $config{repositories}) {
+ $relvcs=join("\n", map {
+ s/"//g; # avoid quotes just in case
+ qq{<link rel="vcs-$config{rcs}" href="$_" title="wiki $config{rcs} repository" />}
+ } @{$config{repositories}});
+
+ hook(type => "pagetemplate", id => "repolist", call => \&pagetemplate);
+ }
+}
+
+sub pagetemplate (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $template=$params{template};
+
+ if (defined $relvcs && $template->query(name => "relvcs")) {
+ $template->param(relvcs => $relvcs);
+ }
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "search", call => \&getsetup);
hook(type => "checkconfig", id => "search", call => \&checkconfig);
hook(type => "pagetemplate", id => "search", call => \&pagetemplate);
- hook(type => "sanitize", id => "search", call => \&index);
+ hook(type => "postscan", id => "search", call => \&index);
hook(type => "delete", id => "search", call => \&delete);
hook(type => "cgi", id => "search", call => \&cgi);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ omega_cgi => {
+ type => "string",
+ example => "/usr/lib/cgi-bin/omega/omega",
+ description => "path to the omega cgi program",
+ safe => 0, # external program
+ rebuild => 0,
+ },
+}
-sub checkconfig () { #{{{
+sub checkconfig () {
foreach my $required (qw(url cgiurl)) {
if (! length $config{$required}) {
- error(sprintf(gettext("Must specify %s when using the search plugin"), $required));
+ error(sprintf(gettext("Must specify %s when using the %s plugin"), $required, 'search'));
}
}
- if (! exists $config{omega_cgi}) {
+ if (! defined $config{omega_cgi}) {
$config{omega_cgi}="/usr/lib/cgi-bin/omega/omega";
}
-} #}}}
+}
my $form;
-sub pagetemplate (@) { #{{{
+sub pagetemplate (@) {
my %params=@_;
my $page=$params{page};
my $template=$params{template};
$template->param(searchform => $form);
}
-} #}}}
+}
my $scrubber;
my $stemmer;
-sub index (@) { #{{{
+sub index (@) {
my %params=@_;
-
- return $params{content} if $IkiWiki::preprocessing{$params{destpage}};
setupfiles();
my $db=xapiandb();
my $doc=Search::Xapian::Document->new();
- my $caption=IkiWiki::pagetitle($params{page});
+ my $caption=pagetitle($params{page});
my $title;
if (exists $pagestate{$params{page}}{meta} &&
exists $pagestate{$params{page}}{meta}{title}) {
$tg->index_text($caption, 2);
$tg->index_text($title, 2) if $title ne $caption;
$tg->index_text($toindex);
- $tg->index_text(lc($title), 1, "ZS"); # for title:foo
+ $tg->index_text(lc($title), 1, "S"); # for title:foo
foreach my $link (@{$links{$params{page}}}) {
- $tg->index_text(lc($link), 1, "ZLINK"); # for link:bar
+ $tg->index_text(lc($link), 1, "XLINK"); # for link:bar
}
$doc->add_term($pageterm);
$db->replace_document_by_term($pageterm, $doc);
+}
- return $params{content};
-} #}}}
-
-sub delete (@) { #{{{
+sub delete (@) {
my $db=xapiandb();
foreach my $page (@_) {
my $pageterm=pageterm(pagename($page));
$db->delete_document_by_term($pageterm) if defined $pageterm;
}
-} #}}}
+}
-sub cgi ($) { #{{{
+sub cgi ($) {
my $cgi=shift;
if (defined $cgi->param('P')) {
noimageinline => 1, linktext => "Help");
exec($config{omega_cgi}) || error("$config{omega_cgi} failed: $!");
}
-} #}}}
+}
-sub pageterm ($) { #{{{
+sub pageterm ($) {
my $page=shift;
# 240 is the number used by omindex to decide when to hash an
else {
return "U:".$page;
}
-} #}}}
+}
my $db;
-sub xapiandb () { #{{{
+sub xapiandb () {
if (! defined $db) {
eval q{
use Search::Xapian;
Search::Xapian::DB_CREATE_OR_OPEN());
}
return $db;
-} #}}}
+}
{
my $setup=0;
-sub setupfiles () { #{{{
+sub setupfiles () {
if (! $setup and (! -e $config{wikistatedir}."/xapian" || $config{rebuild})) {
writefile("omega.conf", $config{wikistatedir}."/xapian",
"database_dir .\n".
readfile(IkiWiki::template_file("searchquery.tmpl"))));
$setup=1;
}
-} #}}}
+}
}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "shortcut", call => \&getsetup);
hook(type => "checkconfig", id => "shortcut", call => \&checkconfig);
hook(type => "preprocess", id => "shortcut", call => \&preprocess_shortcut);
-} #}}}
+}
-sub checkconfig () { #{{{
- # Preprocess the shortcuts page to get all the available shortcuts
- # defined before other pages are rendered.
- my $srcfile=srcfile("shortcuts.mdwn", 1);
- if (! defined $srcfile) {
- error(gettext("shortcut plugin will not work without a shortcuts.mdwn"));
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub checkconfig () {
+ if (defined $config{srcdir} && length $config{srcdir}) {
+ # Preprocess the shortcuts page to get all the available shortcuts
+ # defined before other pages are rendered.
+ my $srcfile=srcfile("shortcuts.".$config{default_pageext}, 1);
+ if (! defined $srcfile) {
+ $srcfile=srcfile("shortcuts.mdwn", 1);
+ }
+ if (! defined $srcfile) {
+ print STDERR sprintf(gettext("shortcut plugin will not work without %s"),
+ "shortcuts.".$config{default_pageext})."\n";
+ }
+ else {
+ IkiWiki::preprocess("shortcuts", "shortcuts", readfile($srcfile));
+ }
}
- IkiWiki::preprocess("shortcuts", "shortcuts", readfile($srcfile));
-} # }}}
+}
-sub preprocess_shortcut (@) { #{{{
+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},
+ shortcut => 1,
call => sub { shortcut_expand($params{url}, $params{desc}, @_) });
#translators: This is used to display what shortcuts are defined.
#translators: First parameter is the name of the shortcut, the second
#translators: is an URL.
return sprintf(gettext("shortcut %s points to <i>%s</i>"), $params{name}, $params{url});
-} # }}}
+}
-sub shortcut_expand ($$@) { #{{{
+sub shortcut_expand ($$@) {
my $url=shift;
my $desc=shift;
my %params=@_;
}
return "<a href=\"$url\">$desc</a>";
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "sidebar", call => \&getsetup);
hook(type => "pagetemplate", id => "sidebar", call => \&pagetemplate);
-} # }}}
+}
-sub sidebar_content ($) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub sidebar_content ($) {
my $page=shift;
my $sidebar_page=bestlink($page, "sidebar") || return;
IkiWiki::filter($sidebar_page, $page, $content))));
}
-} # }}}
+}
-sub pagetemplate (@) { #{{{
+sub pagetemplate (@) {
my %params=@_;
my $page=$params{page};
$template->param(sidebar => $content);
}
}
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "signinedit", call => \&getsetup);
hook(type => "canedit", id => "signinedit", call => \&canedit,
last => 1);
-} # }}}
+}
-sub canedit ($$$) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+}
+
+sub canedit ($$$) {
my $page=shift;
my $cgi=shift;
my $session=shift;
else {
return "";
}
-} #}}}
+}
1
+++ /dev/null
-#!/usr/bin/perl
-# Ikiwiki skeleton plugin. Replace "skeleton" with the name of your plugin
-# in the lines below, remove hooks you don't use, and flesh out the code to
-# make it do something.
-package IkiWiki::Plugin::skeleton;
-
-use warnings;
-use strict;
-use IkiWiki 2.00;
-
-sub import { #{{{
- hook(type => "getopt", id => "skeleton", call => \&getopt);
- hook(type => "checkconfig", id => "skeleton", call => \&checkconfig);
- hook(type => "needsbuild", id => "skeleton", call => \&needsbuild);
- hook(type => "preprocess", id => "skeleton", call => \&preprocess);
- hook(type => "filter", id => "skeleton", call => \&filter);
- hook(type => "linkify", id => "skeleton", call => \&linkify);
- hook(type => "scan", id => "skeleton", call => \&scan);
- hook(type => "htmlize", id => "skeleton", call => \&htmlize);
- hook(type => "sanitize", id => "skeleton", call => \&sanitize);
- hook(type => "format", id => "skeleton", call => \&format);
- hook(type => "pagetemplate", id => "skeleton", call => \&pagetemplate);
- hook(type => "templatefile", id => "skeleton", call => \&templatefile);
- hook(type => "delete", id => "skeleton", call => \&delete);
- hook(type => "change", id => "skeleton", call => \&change);
- hook(type => "cgi", id => "skeleton", call => \&cgi);
- hook(type => "auth", id => "skeleton", call => \&auth);
- hook(type => "sessioncgi", id => "skeleton", call => \&sessioncgi);
- hook(type => "canedit", id => "skeleton", call => \&canedit);
- hook(type => "editcontent", id => "skeleton", call => \&editcontent);
- hook(type => "formbuilder_setup", id => "skeleton", call => \&formbuilder_setup);
- hook(type => "formbuilder", id => "skeleton", call => \&formbuilder);
- hook(type => "savestate", id => "skeleton", call => \&savestate);
-} # }}}
-
-sub getopt () { #{{{
- debug("skeleton plugin getopt");
-} #}}}
-
-sub checkconfig () { #{{{
- debug("skeleton plugin checkconfig");
-} #}}}
-
-sub needsbuild () { #{{{
- debug("skeleton plugin needsbuild");
-} #}}}
-
-sub preprocess (@) { #{{{
- my %params=@_;
-
- return "skeleton plugin result";
-} # }}}
-
-sub filter (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running as filter");
-
- return $params{content};
-} # }}}
-
-sub linkify (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running as linkify");
-
- return $params{content};
-} # }}}
-
-sub scan (@) { #{{{a
- my %params=@_;
-
- debug("skeleton plugin running as scan");
-} # }}}
-
-sub htmlize (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running as htmlize");
-
- return $params{content};
-} # }}}
-
-sub sanitize (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running as a sanitizer");
-
- return $params{content};
-} # }}}
-
-sub format (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running as a formatter");
-
- return $params{content};
-} # }}}
-
-sub pagetemplate (@) { #{{{
- my %params=@_;
- my $page=$params{page};
- my $template=$params{template};
-
- debug("skeleton plugin running as a pagetemplate hook");
-} # }}}
-
-sub templatefile (@) { #{{{
- my %params=@_;
- my $page=$params{page};
-
- debug("skeleton plugin running as a templatefile hook");
-} # }}}
-
-sub delete (@) { #{{{
- my @files=@_;
-
- debug("skeleton plugin told that files were deleted: @files");
-} #}}}
-
-sub change (@) { #{{{
- my @files=@_;
-
- debug("skeleton plugin told that changed files were rendered: @files");
-} #}}}
-
-sub cgi ($) { #{{{
- my $cgi=shift;
-
- debug("skeleton plugin running in cgi");
-} #}}}
-
-sub auth ($$) { #{{{
- my $cgi=shift;
- my $session=shift;
-
- debug("skeleton plugin running in auth");
-} #}}}
-
-sub sessionncgi ($$) { #{{{
- my $cgi=shift;
- my $session=shift;
-
- debug("skeleton plugin running in sessioncgi");
-} #}}}
-
-sub canedit ($$$) { #{{{
- my $page=shift;
- my $cgi=shift;
- my $session=shift;
-
- debug("skeleton plugin running in canedit");
-} #}}}
-
-sub editcontent ($$$) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running in editcontent");
-
- return $params{content};
-} #}}}
-
-sub formbuilder_setup (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running in formbuilder_setup");
-} # }}}
-
-sub formbuilder (@) { #{{{
- my %params=@_;
-
- debug("skeleton plugin running in formbuilder");
-} # }}}
-
-sub savestate () { #{{{
- debug("skeleton plugin running in savestate");
-} #}}}
-
-1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki skeleton plugin. Replace "skeleton" with the name of your plugin
+# in the lines below, remove hooks you don't use, and flesh out the code to
+# make it do something.
+package IkiWiki::Plugin::skeleton;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getopt", id => "skeleton", call => \&getopt);
+ hook(type => "getsetup", id => "skeleton", call => \&getsetup);
+ hook(type => "checkconfig", id => "skeleton", call => \&checkconfig);
+ hook(type => "refresh", id => "skeleton", call => \&refresh);
+ hook(type => "needsbuild", id => "skeleton", call => \&needsbuild);
+ hook(type => "preprocess", id => "skeleton", call => \&preprocess);
+ hook(type => "filter", id => "skeleton", call => \&filter);
+ hook(type => "linkify", id => "skeleton", call => \&linkify);
+ hook(type => "scan", id => "skeleton", call => \&scan);
+ hook(type => "htmlize", id => "skeleton", call => \&htmlize);
+ hook(type => "sanitize", id => "skeleton", call => \&sanitize);
+ hook(type => "postscan", id => "skeleton", call => \&postscan);
+ hook(type => "format", id => "skeleton", call => \&format);
+ hook(type => "pagetemplate", id => "skeleton", call => \&pagetemplate);
+ hook(type => "templatefile", id => "skeleton", call => \&templatefile);
+ hook(type => "delete", id => "skeleton", call => \&delete);
+ hook(type => "change", id => "skeleton", call => \&change);
+ hook(type => "cgi", id => "skeleton", call => \&cgi);
+ hook(type => "auth", id => "skeleton", call => \&auth);
+ hook(type => "sessioncgi", id => "skeleton", call => \&sessioncgi);
+ hook(type => "canedit", id => "skeleton", call => \&canedit);
+ hook(type => "canremove", id => "skeleton", call => \&canremove);
+ hook(type => "canrename", id => "skeleton", call => \&canrename);
+ hook(type => "checkcontent", id => "skeleton", call => \&checkcontent);
+ hook(type => "editcontent", id => "skeleton", call => \&editcontent);
+ hook(type => "formbuilder_setup", id => "skeleton", call => \&formbuilder_setup);
+ hook(type => "formbuilder", id => "skeleton", call => \&formbuilder);
+ hook(type => "renamepage", id => "skeleton", call => \&renamepage);
+ hook(type => "rename", id => "skeleton", call => \&rename);
+ hook(type => "savestate", id => "skeleton", call => \&savestate);
+}
+
+sub getopt () {
+ debug("skeleton plugin getopt");
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ skeleton => {
+ type => "boolean",
+ example => 0,
+ description => "example option",
+ safe => 0,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
+ debug("skeleton plugin checkconfig");
+}
+
+sub refresh () {
+ debug("skeleton plugin refresh");
+}
+
+sub needsbuild () {
+ debug("skeleton plugin needsbuild");
+}
+
+sub preprocess (@) {
+ my %params=@_;
+
+ return "skeleton plugin result";
+}
+
+sub filter (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as filter");
+
+ return $params{content};
+}
+
+sub linkify (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as linkify");
+
+ return $params{content};
+}
+
+sub scan (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as scan");
+}
+
+sub htmlize (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as htmlize");
+
+ return $params{content};
+}
+
+sub sanitize (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as a sanitizer");
+
+ return $params{content};
+}
+
+sub postscan (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as postscan");
+}
+
+sub format (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running as a formatter");
+
+ return $params{content};
+}
+
+sub pagetemplate (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $template=$params{template};
+
+ debug("skeleton plugin running as a pagetemplate hook");
+}
+
+sub templatefile (@) {
+ my %params=@_;
+ my $page=$params{page};
+
+ debug("skeleton plugin running as a templatefile hook");
+}
+
+sub delete (@) {
+ my @files=@_;
+
+ debug("skeleton plugin told that files were deleted: @files");
+}
+
+sub change (@) {
+ my @files=@_;
+
+ debug("skeleton plugin told that changed files were rendered: @files");
+}
+
+sub cgi ($) {
+ my $cgi=shift;
+
+ debug("skeleton plugin running in cgi");
+}
+
+sub auth ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ debug("skeleton plugin running in auth");
+}
+
+sub sessioncgi ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ debug("skeleton plugin running in sessioncgi");
+}
+
+sub canedit ($$$) {
+ my $page=shift;
+ my $cgi=shift;
+ my $session=shift;
+
+ debug("skeleton plugin running in canedit");
+}
+
+sub canremove (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in canremove");
+}
+
+sub canrename (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in canrename");
+}
+
+sub checkcontent (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in checkcontent");
+}
+
+sub editcontent ($$$) {
+ my %params=@_;
+
+ debug("skeleton plugin running in editcontent");
+
+ return $params{content};
+}
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in formbuilder_setup");
+}
+
+sub formbuilder (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in formbuilder");
+}
+
+sub renamepage (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in renamepage");
+}
+
+sub rename (@) {
+ my %params=@_;
+
+ debug("skeleton plugin running in rename");
+}
+
+sub savestate () {
+ debug("skeleton plugin running in savestate");
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my %smileys;
my $smiley_regexp;
-sub import { #{{{
+sub import {
add_underlay("smiley");
+ hook(type => "getsetup", id => "smiley", call => \&getsetup);
hook(type => "sanitize", id => "smiley", call => \&sanitize);
-} # }}}
+}
-sub build_regexp () { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ # force a rebuild because turning it off
+ # removes the smileys, which would break links
+ rebuild => 1,
+ },
+}
+
+sub build_regexp () {
my $list=readfile(srcfile("smileys.mdwn"));
- while ($list =~ m/^\s*\*\s+\\([^\s]+)\s+\[\[([^]]+)\]\]/mg) {
+ while ($list =~ m/^\s*\*\s+\\\\([^\s]+)\s+\[\[([^]]+)\]\]/mg) {
my $smiley=$1;
my $file=$2;
$smiley_regexp='('.join('|', map { quotemeta }
reverse sort keys %smileys).')';
#debug($smiley_regexp);
-} #}}}
+}
-sub sanitize (@) { #{{{
+sub sanitize (@) {
my %params=@_;
build_regexp() unless defined $smiley_regexp;
$_=$params{content};
return $_ unless length $smiley_regexp;
-
+
MATCH: while (m{(?:^|(?<=\s|>))(\\?)$smiley_regexp(?:(?=\s|<)|$)}g) {
my $escape=$1;
my $smiley=$2;
# Reset pos back to where it was before this test.
pos=$pos;
}
-
+
if ($escape) {
# Remove escape.
substr($_, $epos, 1)="";
+ pos=$epos+1;
}
else {
# Replace the smiley with its expanded value.
- substr($_, $spos, length($smiley))=
- htmllink($params{page}, $params{destpage},
+ my $link=htmllink($params{page}, $params{destpage},
$smileys{$smiley}, linktext => $smiley);
+ substr($_, $spos, length($smiley))=$link;
+ pos=$epos+length($link);
}
}
return $_;
-} # }}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use IPC::Open2;
my $match_num=qr/[-+]?[0-9]+(?:\.[0-9]+)?/;
left => 'TEXT_LEFT',
);
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "sparkline", call => \&getsetup);
hook(type => "preprocess", id => "sparkline", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
my $php;
}
}
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("invalid featurepoint diameter");
}
$x=int($x);
$y=int($y);
if (defined $location) {
$location=$locmap{$location};
if (! defined $location) {
- return "[[sparkline ".gettext("bad featurepoint location")."]]";
+ error gettext("invalid featurepoint location");
}
}
$php.=qq{\$sparkline->SetFeaturePoint($x, $y, '$color', $diameter};
}
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("invalid 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("invalid width value");
}
$php.=qq{\$sparkline->RenderResampled($width, $height);\n};
}
if (! -e "$config{destdir}/$fn") {
my $pid;
- my $sigpipe=0;;
+ my $sigpipe=0;
$SIG{PIPE}=sub { $sigpipe=1 };
$pid=open2(*IN, *OUT, "php");
waitpid $pid, 0;
$SIG{PIPE}="DEFAULT";
if ($sigpipe) {
- return "[[sparkline ".gettext("failed to run php")."]]";
+ error gettext("failed to run php");
}
if (! $params{preview}) {
}
return '<img src="'.urlto($fn, $params{destpage}).'" alt="graph" />';
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::svn;
+
+use warnings;
+use strict;
+use IkiWiki;
+use POSIX qw(setlocale LC_CTYPE);
+
+sub import {
+ hook(type => "checkconfig", id => "svn", call => \&checkconfig);
+ hook(type => "getsetup", id => "svn", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub checkconfig () {
+ if (! defined $config{svnpath}) {
+ $config{svnpath}="trunk";
+ }
+ if (exists $config{svnpath}) {
+ # code depends on the path not having extraneous slashes
+ $config{svnpath}=~tr#/#/#s;
+ $config{svnpath}=~s/\/$//;
+ $config{svnpath}=~s/^\///;
+ }
+ if (defined $config{svn_wrapper} && length $config{svn_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{svn_wrapper},
+ wrappermode => (defined $config{svn_wrappermode} ? $config{svn_wrappermode} : "04755"),
+ };
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ svnrepo => {
+ type => "string",
+ example => "/svn/wiki",
+ description => "subversion repository location",
+ safe => 0, # path
+ rebuild => 0,
+ },
+ svnpath => {
+ type => "string",
+ example => "trunk",
+ description => "path inside repository where the wiki is located",
+ safe => 0, # paranoia
+ rebuild => 0,
+ },
+ svn_wrapper => {
+ type => "string",
+ example => "/svn/wikirepo/hooks/post-commit",
+ description => "svn post-commit hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ svn_wrappermode => {
+ type => "string",
+ example => '04755',
+ description => "mode for svn_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ example => "http://svn.example.org/trunk/[[file]]",
+ description => "viewvc url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ example => "http://svn.example.org/trunk/[[file]]?root=wiki&r1=[[r1]]&r2=[[r2]]",
+ description => "viewvc url to show a diff ([[file]], [[r1]], and [[r2]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+# svn needs LC_CTYPE set to a UTF-8 locale, so try to find one. Any will do.
+sub find_lc_ctype() {
+ my $current = setlocale(LC_CTYPE());
+ return $current if $current =~ m/UTF-?8$/i;
+
+ # Make some obvious attempts to avoid calling `locale -a`
+ foreach my $locale ("$current.UTF-8", "en_US.UTF-8", "en_GB.UTF-8") {
+ return $locale if setlocale(LC_CTYPE(), $locale);
+ }
+
+ # Try to get all available locales and pick the first UTF-8 one found.
+ if (my @locale = grep(/UTF-?8$/i, `locale -a`)) {
+ chomp @locale;
+ return $locale[0] if setlocale(LC_CTYPE(), $locale[0]);
+ }
+
+ # fallback to the current locale
+ return $current;
+}
+$ENV{LC_CTYPE} = $ENV{LC_CTYPE} || find_lc_ctype();
+
+sub svn_info ($$) {
+ my $field=shift;
+ my $file=shift;
+
+ my $info=`LANG=C svn info $file`;
+ my ($ret)=$info=~/^$field: (.*)$/m;
+ return $ret;
+}
+
+sub rcs_update () {
+ if (-d "$config{srcdir}/.svn") {
+ if (system("svn", "update", "--quiet", $config{srcdir}) != 0) {
+ warn("svn update failed\n");
+ }
+ }
+}
+
+sub rcs_prepedit ($) {
+ # Prepares to edit a file under revision control. Returns a token
+ # that must be passed into rcs_commit when the file is ready
+ # for committing.
+ # The file is relative to the srcdir.
+ my $file=shift;
+
+ if (-d "$config{srcdir}/.svn") {
+ # For subversion, return the revision of the file when
+ # editing begins.
+ my $rev=svn_info("Revision", "$config{srcdir}/$file");
+ return defined $rev ? $rev : "";
+ }
+}
+
+sub rcs_commit ($$$;$$) {
+ # Tries to commit the page; returns undef on _success_ and
+ # a version of the page with the rcs's conflict markers on failure.
+ # The file is relative to the srcdir.
+ my $file=shift;
+ my $message=shift;
+ my $rcstoken=shift;
+ my $user=shift;
+ my $ipaddr=shift;
+
+ if (defined $user) {
+ $message="web commit by $user".(length $message ? ": $message" : "");
+ }
+ elsif (defined $ipaddr) {
+ $message="web commit from $ipaddr".(length $message ? ": $message" : "");
+ }
+
+ if (-d "$config{srcdir}/.svn") {
+ # Check to see if the page has been changed by someone
+ # else since rcs_prepedit was called.
+ my ($oldrev)=$rcstoken=~/^([0-9]+)$/; # untaint
+ my $rev=svn_info("Revision", "$config{srcdir}/$file");
+ if (defined $rev && defined $oldrev && $rev != $oldrev) {
+ # Merge their changes into the file that we've
+ # changed.
+ if (system("svn", "merge", "--quiet", "-r$oldrev:$rev",
+ "$config{srcdir}/$file", "$config{srcdir}/$file") != 0) {
+ warn("svn merge -r$oldrev:$rev failed\n");
+ }
+ }
+
+ if (system("svn", "commit", "--quiet",
+ "--encoding", "UTF-8", "-m",
+ IkiWiki::possibly_foolish_untaint($message),
+ $config{srcdir}) != 0) {
+ my $conflict=readfile("$config{srcdir}/$file");
+ if (system("svn", "revert", "--quiet", "$config{srcdir}/$file") != 0) {
+ warn("svn revert failed\n");
+ }
+ return $conflict;
+ }
+ }
+ return undef # success
+}
+
+sub rcs_commit_staged ($$$) {
+ # Commits all staged changes. Changes can be staged using rcs_add,
+ # rcs_remove, and rcs_rename.
+ my ($message, $user, $ipaddr)=@_;
+
+ if (defined $user) {
+ $message="web commit by $user".(length $message ? ": $message" : "");
+ }
+ elsif (defined $ipaddr) {
+ $message="web commit from $ipaddr".(length $message ? ": $message" : "");
+ }
+
+ if (system("svn", "commit", "--quiet",
+ "--encoding", "UTF-8", "-m",
+ IkiWiki::possibly_foolish_untaint($message),
+ $config{srcdir}) != 0) {
+ warn("svn commit failed\n");
+ return 1; # failure
+ }
+ return undef # success
+}
+
+sub rcs_add ($) {
+ # filename is relative to the root of the srcdir
+ my $file=shift;
+
+ if (-d "$config{srcdir}/.svn") {
+ my $parent=IkiWiki::dirname($file);
+ while (! -d "$config{srcdir}/$parent/.svn") {
+ $file=$parent;
+ $parent=IkiWiki::dirname($file);
+ }
+
+ if (system("svn", "add", "--quiet", "$config{srcdir}/$file") != 0) {
+ warn("svn add failed\n");
+ }
+ }
+}
+
+sub rcs_remove ($) {
+ # filename is relative to the root of the srcdir
+ my $file=shift;
+
+ if (-d "$config{srcdir}/.svn") {
+ if (system("svn", "rm", "--force", "--quiet", "$config{srcdir}/$file") != 0) {
+ warn("svn rm failed\n");
+ }
+ }
+}
+
+sub rcs_rename ($$) {
+ # filenames relative to the root of the srcdir
+ my ($src, $dest)=@_;
+
+ if (-d "$config{srcdir}/.svn") {
+ # Add parent directory for $dest
+ my $parent=IkiWiki::dirname($dest);
+ if (! -d "$config{srcdir}/$parent/.svn") {
+ while (! -d "$config{srcdir}/$parent/.svn") {
+ $parent=IkiWiki::dirname($dest);
+ }
+ if (system("svn", "add", "--quiet", "$config{srcdir}/$parent") != 0) {
+ warn("svn add $parent failed\n");
+ }
+ }
+
+ if (system("svn", "mv", "--force", "--quiet",
+ "$config{srcdir}/$src", "$config{srcdir}/$dest") != 0) {
+ warn("svn rename failed\n");
+ }
+ }
+}
+
+sub rcs_recentchanges ($) {
+ my $num=shift;
+ my @ret;
+
+ return unless -d "$config{srcdir}/.svn";
+
+ eval q{
+ use Date::Parse;
+ use XML::SAX;
+ use XML::Simple;
+ };
+ error($@) if $@;
+
+ # avoid using XML::SAX::PurePerl, it's buggy with UTF-8 data
+ my @parsers = map { ${$_}{Name} } @{XML::SAX->parsers()};
+ do {
+ $XML::Simple::PREFERRED_PARSER = pop @parsers;
+ } until $XML::Simple::PREFERRED_PARSER ne 'XML::SAX::PurePerl';
+
+ # --limit is only supported on Subversion 1.2.0+
+ my $svn_version=`svn --version -q`;
+ my $svn_limit='';
+ $svn_limit="--limit $num"
+ if $svn_version =~ /\d\.(\d)\.\d/ && $1 >= 2;
+
+ my $svn_url=svn_info("URL", $config{srcdir});
+ my $xml = XMLin(scalar `svn $svn_limit --xml -v log '$svn_url'`,
+ ForceArray => [ 'logentry', 'path' ],
+ GroupTags => { paths => 'path' },
+ KeyAttr => { path => 'content' },
+ );
+ foreach my $logentry (@{$xml->{logentry}}) {
+ my (@pages, @message);
+
+ my $rev = $logentry->{revision};
+ my $user = $logentry->{author};
+
+ my $when=str2time($logentry->{date}, 'UTC');
+
+ foreach my $msgline (split(/\n/, $logentry->{msg})) {
+ push @message, { line => $msgline };
+ }
+
+ my $committype="web";
+ if (defined $message[0] &&
+ $message[0]->{line}=~/$config{web_commit_regexp}/) {
+ $user=defined $2 ? "$2" : "$3";
+ $message[0]->{line}=$4;
+ }
+ else {
+ $committype="svn";
+ }
+
+ foreach my $file (keys %{$logentry->{paths}}) {
+ if (length $config{svnpath}) {
+ next unless $file=~/^\/\Q$config{svnpath}\E\/([^ ]+)(?:$|\s)/;
+ $file=$1;
+ }
+
+ my $diffurl=defined $config{diffurl} ? $config{diffurl} : "";
+ $diffurl=~s/\[\[file\]\]/$file/g;
+ $diffurl=~s/\[\[r1\]\]/$rev - 1/eg;
+ $diffurl=~s/\[\[r2\]\]/$rev/g;
+
+ push @pages, {
+ page => pagename($file),
+ diffurl => $diffurl,
+ } if length $file;
+ }
+ push @ret, {
+ rev => $rev,
+ user => $user,
+ committype => $committype,
+ when => $when,
+ message => [@message],
+ pages => [@pages],
+ } if @pages;
+ return @ret if @ret >= $num;
+ }
+
+ return @ret;
+}
+
+sub rcs_diff ($) {
+ my $rev=IkiWiki::possibly_foolish_untaint(int(shift));
+ return `svnlook diff $config{svnrepo} -r$rev --no-diff-deleted`;
+}
+
+sub rcs_getctime ($) {
+ my $file=shift;
+
+ my $svn_log_infoline=qr/^r\d+\s+\|\s+[^\s]+\s+\|\s+(\d+-\d+-\d+\s+\d+:\d+:\d+\s+[-+]?\d+).*/;
+
+ my $child = open(SVNLOG, "-|");
+ if (! $child) {
+ exec("svn", "log", $file) || error("svn log $file failed to run");
+ }
+
+ my $date;
+ while (<SVNLOG>) {
+ if (/$svn_log_infoline/) {
+ $date=$1;
+ }
+ }
+ close SVNLOG || warn "svn log $file exited $?";
+
+ if (! defined $date) {
+ warn "failed to parse svn log for $file\n";
+ return 0;
+ }
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+ $date=str2time($date);
+ debug("found ctime ".localtime($date)." for $file");
+ return $date;
+}
+
+1
use warnings;
use strict;
use Encode;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
- hook(type => "preprocess", id => "table", call => \&preprocess);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "table", call => \&getsetup);
+ hook(type => "preprocess", id => "table", call => \&preprocess, scan => 1);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params =(
format => 'auto',
- header => 'yes',
+ header => 'row',
@_
);
if (exists $params{file}) {
- if (! $pagesources{$params{file}}) {
- return "[[table ".gettext("cannot find file")."]]";
+ if (! exists $pagesources{$params{file}}) {
+ error gettext("cannot find file");
}
$params{data} = readfile(srcfile($params{file}));
add_depends($params{page}, $params{file});
}
+ if (! defined wantarray) {
+ # scan mode -- if the table uses an external file, need to
+ # scan that file too.
+ return unless exists $params{file};
+
+ IkiWiki::run_hooks(scan => sub {
+ shift->(
+ page => $params{page},
+ content => $params{data},
+ );
+ });
+
+ # Preprocess in scan-only mode.
+ IkiWiki::preprocess($params{page}, $params{page}, $params{data}, 1);
+
+ return;
+ }
+
if (lc $params{format} eq 'auto') {
# first try the more simple format
if (is_dsv_data($params{data})) {
defined $params{delimiter} ? $params{delimiter} : ",",);
# linkify after parsing since html link quoting can
# confuse CSV parsing
- if (! exists $params{file}) {
- @data=map {
- [ map {
- IkiWiki::linkify($params{page},
- $params{destpage}, $_);
- } @$_ ]
- } @data;
- }
+ @data=map {
+ [ map {
+ IkiWiki::linkify($params{page},
+ $params{destpage}, $_);
+ } @$_ ]
+ } @data;
}
elsif (lc $params{format} eq 'dsv') {
# linkify before parsing since wikilinks can contain the
# delimiter
- if (! exists $params{file}) {
- $params{data} = IkiWiki::linkify($params{page},
- $params{destpage}, $params{data});
- }
+ $params{data} = IkiWiki::linkify($params{page},
+ $params{destpage}, $params{data});
@data=split_dsv($params{data},
defined $params{delimiter} ? $params{delimiter} : "|",);
}
else {
- return "[[table ".gettext("unknown data format")."]]";
+ error gettext("unknown data format");
}
my $header;
- if (lc($params{header}) eq "yes") {
+ if (lc($params{header}) eq "row" || IkiWiki::yesno($params{header})) {
$header=shift @data;
}
if (! @data) {
- return "[[table ".gettext("empty data")."]]";
+ error gettext("empty data");
}
my @lines;
? "<table class=\"".$params{class}.'">'
: '<table>';
push @lines, "\t<thead>",
- genrow($params{page}, $params{destpage}, "th", @$header),
+ genrow(\%params, "th", @$header),
"\t</thead>" if defined $header;
push @lines, "\t<tbody>" if defined $header;
- push @lines, genrow($params{page}, $params{destpage}, "td", @$_)
- foreach @data;
+ push @lines, genrow(\%params, "td", @$_) foreach @data;
push @lines, "\t</tbody>" if defined $header;
push @lines, '</table>';
my $html = join("\n", @lines);
else {
return $html;
}
-} #}}}
+}
-sub is_dsv_data ($) { #{{{
+sub is_dsv_data ($) {
my $text = shift;
my ($line) = split(/\n/, $text);
return $line =~ m{.+\|};
}
-sub split_csv ($$) { #{{{
+sub split_csv ($$) {
my @text_lines = split(/\n/, shift);
my $delimiter = shift;
}
return @data;
-} #}}}
+}
-sub split_dsv ($$) { #{{{
+sub split_dsv ($$) {
my @text_lines = split(/\n/, shift);
my $delimiter = shift;
$delimiter="|" unless defined $delimiter;
}
return @data;
-} #}}}
+}
-sub genrow ($$$@) { #{{{
- my $page = shift;
- my $destpage = shift;
+sub genrow ($@) {
+ my %params=%{shift()};
my $elt = shift;
my @data = @_;
+ my $page=$params{page};
+ my $destpage=$params{destpage};
+ my $type=pagetype($pagesources{$page});
+
my @ret;
push @ret, "\t\t<tr>";
for (my $x=0; $x < @data; $x++) {
- my $cell=htmlize($page, $destpage, $data[$x]);
+ my $cell=IkiWiki::htmlize($page, $destpage, $type,
+ IkiWiki::preprocess($page, $destpage, $data[$x]));
+
+ # automatic colspan for empty cells
my $colspan=1;
while ($x+1 < @data && $data[$x+1] eq '') {
$x++;
$colspan++;
}
+
+ # check if the first column should be a header
+ my $e=$elt;
+ if ($x == 0 && lc($params{header}) eq "column") {
+ $e="th";
+ }
+
if ($colspan > 1) {
- push @ret, "\t\t\t<$elt colspan=\"$colspan\">$cell</$elt>"
+ push @ret, "\t\t\t<$e colspan=\"$colspan\">$cell</$e>"
}
else {
- push @ret, "\t\t\t<$elt>$cell</$elt>"
+ push @ret, "\t\t\t<$e>$cell</$e>"
}
}
push @ret, "\t\t</tr>";
return @ret;
-} #}}}
-
-sub htmlize ($$$) { #{{{
- my $page = shift;
- my $destpage = shift;
-
- return IkiWiki::htmlize($page, $destpage, pagetype($pagesources{$page}),
- IkiWiki::preprocess($page, $destpage, shift));
}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
my %tags;
-sub import { #{{{
+sub import {
hook(type => "getopt", id => "tag", call => \&getopt);
+ hook(type => "getsetup", id => "tag", call => \&getsetup);
hook(type => "preprocess", id => "tag", call => \&preprocess_tag, scan => 1);
hook(type => "preprocess", id => "taglink", call => \&preprocess_taglink, scan => 1);
hook(type => "pagetemplate", id => "tag", call => \&pagetemplate);
-} # }}}
+}
-sub getopt () { #{{{
+sub getopt () {
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
GetOptions("tagbase=s" => \$config{tagbase});
-} #}}}
+}
-sub tagpage ($) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ tagbase => {
+ type => "string",
+ example => "tag",
+ description => "parent page tags are located under",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub tagpage ($) {
my $tag=shift;
- if (exists $config{tagbase} &&
+ if ($tag !~ m{^\.?/} &&
defined $config{tagbase}) {
- $tag=$config{tagbase}."/".$tag;
+ $tag="/".$config{tagbase}."/".$tag;
+ $tag=~y#/#/#s; # squash dups
}
return $tag;
-} #}}}
+}
+
+sub taglink ($$$;@) {
+ my $page=shift;
+ my $destpage=shift;
+ my $tag=shift;
+ my %opts=@_;
-sub preprocess_tag (@) { #{{{
+ return htmllink($page, $destpage, tagpage($tag), %opts);
+}
+
+sub preprocess_tag (@) {
if (! @_) {
return "";
}
delete $params{preview};
foreach my $tag (keys %params) {
- $tag=IkiWiki::linkpage($tag);
+ $tag=linkpage($tag);
$tags{$page}{$tag}=1;
# hidden WikiLink
- push @{$links{$page}}, tagpage($tag);
+ add_link($page, tagpage($tag));
}
return "";
-} # }}}
+}
-sub preprocess_taglink (@) { #{{{
+sub preprocess_taglink (@) {
if (! @_) {
return "";
}
my %params=@_;
return join(" ", map {
if (/(.*)\|(.*)/) {
- my $tag=IkiWiki::linkpage($2);
+ my $tag=linkpage($2);
$tags{$params{page}}{$tag}=1;
- push @{$links{$params{page}}}, tagpage($tag);
- return htmllink($params{page}, $params{destpage},
- tagpage($tag),
- linktext => IkiWiki::pagetitle($1));
+ add_link($params{page}, tagpage($tag));
+ return taglink($params{page}, $params{destpage}, $tag,
+ linktext => pagetitle($1));
}
else {
- my $tag=IkiWiki::linkpage($_);
+ my $tag=linkpage($_);
$tags{$params{page}}{$tag}=1;
- push @{$links{$params{page}}}, tagpage($tag);
- return htmllink($params{page}, $params{destpage},
- tagpage($tag));
+ add_link($params{page}, tagpage($tag));
+ return taglink($params{page}, $params{destpage}, $tag);
}
}
grep {
$_ ne 'page' && $_ ne 'destpage' && $_ ne 'preview'
} keys %params);
-} # }}}
+}
-sub pagetemplate (@) { #{{{
+sub pagetemplate (@) {
my %params=@_;
my $page=$params{page};
my $destpage=$params{destpage};
$template->param(tags => [
map {
- link => htmllink($page, $destpage, tagpage($_),
- rel => "tag")
+ link => taglink($page, $destpage, $_, rel => "tag")
}, sort keys %{$tags{$page}}
]) if exists $tags{$page} && %{$tags{$page}} && $template->query(name => "tags");
sort keys %{$tags{$page}}]);
}
}
-} # }}}
+}
+
+package IkiWiki::PageSpec;
+
+sub match_tagged ($$;@) {
+ my $page = shift;
+ my $glob = shift;
+ return match_link($page, IkiWiki::Plugin::tag::tagpage($glob));
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use HTML::Template;
use Encode;
-sub import { #{{{
- hook(type => "preprocess", id => "template", call => \&preprocess);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "template", call => \&getsetup);
+ hook(type => "preprocess", id => "template", call => \&preprocess,
+ scan => 1);
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+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}";
my $template_file=$pagesources{$template_page};
return sprintf(gettext("template %s not found"),
- htmllink($params{page}, $params{destpage}, $template_page))
+ htmllink($params{page}, $params{destpage}, "/".$template_page))
unless defined $template_file;
my $template;
);
};
if ($@) {
- return "[[template ".gettext("failed to process:")." $@]]";
+ error gettext("failed to process:")." $@"
}
+ $params{basename}=IkiWiki::basename($params{page});
+
foreach my $param (keys %params) {
if ($template->query(name => $param)) {
$template->param($param =>
}
}
+ # This needs to run even in scan mode, in order to process
+ # links and other metadata includes via the template.
+ my $scan=! defined wantarray;
+
return IkiWiki::preprocess($params{page}, $params{destpage},
IkiWiki::filter($params{page}, $params{destpage},
- $template->output));
-} # }}}
+ $template->output), $scan);
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "testpagespec", call => \&getsetup);
hook(type => "preprocess", id => "testpagespec", call => \&preprocess);
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub preprocess (@) {
my %params=@_;
foreach my $param (qw{match pagespec}) {
if (! exists $params{$param}) {
- return "[[testpagespec $param parameter is required]]";
+ error sprintf(gettext("%s parameter is required"), $param);
}
}
else {
return "no match: $ret";
}
-} # }}}
+}
1
use Digest::MD5 qw(md5_hex);
use File::Temp qw(tempdir);
use HTML::Entities;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
- hook(type => "preprocess", id => "teximg", call => \&preprocess);
-} #}}}
+my $default_prefix = <<EOPREFIX;
+\\documentclass{article}
+\\usepackage{amsmath}
+\\usepackage{amsfonts}
+\\usepackage{amssymb}
+\\pagestyle{empty}
+\\begin{document}
+EOPREFIX
+
+my $default_postfix = '\\end{document}';
-sub preprocess (@) { #{{{
+sub import {
+ hook(type => "getsetup", id => "teximg", call => \&getsetup);
+ hook(type => "preprocess", id => "teximg", call => \&preprocess);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ teximg_dvipng => {
+ type => "boolean",
+ description => "Should teximg use dvipng to render, or dvips and convert?",
+ safe => 0,
+ rebuild => undef,
+ },
+ teximg_prefix => {
+ type => "string",
+ example => $default_prefix,
+ description => "LaTeX prefix for teximg plugin",
+ safe => 0, # Not sure how secure LaTeX is...
+ rebuild => 1,
+ },
+ teximg_postfix => {
+ type => "string",
+ example => $default_postfix,
+ description => "LaTeX postfix for teximg plugin",
+ safe => 0, # Not sure how secure LaTeX is...
+ rebuild => 1,
+ },
+}
+
+sub preprocess (@) {
my %params = @_;
my $height = $params{height};
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")
}
-} #}}}
+}
-sub check_height ($) { #{{{
+sub check_height ($) {
# Since latex doesn't support unlimited scaling this function
# returns the closest supported size.
my $height =shift;
}
}
return $ret;
-} #}}}
+}
-sub create ($$$) { #{{{
+sub create ($$$) {
# This function calls the image generating function and returns
# the <img .. /> for the generated image.
my $code = shift;
.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>";
}
-} #}}}
+}
-sub gen_image ($$$$) { #{{{
+sub gen_image ($$$$) {
# Actually creates the image.
my $code = shift;
my $height = shift;
my $digest = shift;
my $imagedir = shift;
- #TODO This should move into the setup file.
- my $tex = '\documentclass['.$height.'pt]{scrartcl}';
- $tex .= '\usepackage[version=3]{mhchem}';
- $tex .= '\usepackage{amsmath}';
- $tex .= '\usepackage{amsfonts}';
- $tex .= '\usepackage{amssymb}';
- $tex .= '\pagestyle{empty}';
- $tex .= '\begin{document}';
+ if (!defined $config{teximg_prefix}) {
+ $config{teximg_prefix} = $default_prefix;
+ }
+ if (!defined $config{teximg_postfix}) {
+ $config{teximg_postfix} = $default_postfix;
+ }
+ if (!defined $config{teximg_dvipng}) {
+ $config{teximg_dvipng} = length `which dvipng 2>/dev/null`;
+ }
+
+ my $tex = $config{teximg_prefix};
$tex .= '$$'.$code.'$$';
- $tex .= '\end{document}';
+ $tex .= $config{teximg_postfix};
+ $tex =~ s!\\documentclass{article}!\\documentclass[${height}pt]{article}!g;
+ $tex =~ s!\\documentclass{scrartcl}!\\documentclass[${height}pt]{scrartcl}!g;
my $tmp = eval { create_tmp_dir($digest) };
if (! $@ &&
writefile("$digest.tex", $tmp, $tex) &&
system("cd $tmp; latex --interaction=nonstopmode $tmp/$digest.tex > /dev/null") == 0 &&
- system("dvips -E $tmp/$digest.dvi -o $tmp/$digest.ps 2> $tmp/$digest.log") == 0 &&
# ensure destination directory exists
writefile("$imagedir/$digest.png", $config{destdir}, "") &&
- system("convert -density 120 -trim -transparent \"#FFFFFF\" $tmp/$digest.ps $config{destdir}/$imagedir/$digest.png > $tmp/$digest.log") == 0) {
+ (($config{teximg_dvipng} &&
+ system("dvipng -D 120 -bg Transparent -T tight -o $config{destdir}/$imagedir/$digest.png $tmp/$digest.dvi > $tmp/$digest.log") == 0
+ ) || (!$config{teximg_dvipng} &&
+ system("dvips -E $tmp/$digest.dvi -o $tmp/$digest.ps 2> $tmp/$digest.log") == 0 &&
+ system("convert -density 120 -trim -transparent \"#FFFFFF\" $tmp/$digest.ps $config{destdir}/$imagedir/$digest.png > $tmp/$digest.log") == 0
+ ))) {
return 1;
}
else {
return 0;
}
-} #}}}
+}
-sub create_tmp_dir ($) { #{{{
+sub create_tmp_dir ($) {
# Create a temp directory, it will be removed when ikiwiki exits.
my $base = shift;
my $template = $base.".XXXXXXXXXX";
my $tmpdir = tempdir($template, TMPDIR => 1, CLEANUP => 1);
return $tmpdir;
-} #}}}
+}
-sub check ($) { #{{{
+sub check ($) {
# Check if the code is ok
my $code = shift;
}
}
return 1;
-} #}}}
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use Encode;
-sub import { #{{{
- hook(type => "htmlize", id => "txtl", call => \&htmlize);
-} # }}}
+sub import {
+ hook(type => "getsetup", id => "textile", call => \&getsetup);
+ hook(type => "htmlize", id => "txtl", call => \&htmlize, longname => "Textile");
+}
-sub htmlize (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+}
+
+sub htmlize (@) {
my %params=@_;
my $content = decode_utf8(encode_utf8($params{content}));
eval q{use Text::Textile};
return $content if $@;
return Text::Textile::textile($content);
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::tla;
+
+use warnings;
+use strict;
+use IkiWiki;
+
+sub import {
+ hook(type => "checkconfig", id => "tla", call => \&checkconfig);
+ hook(type => "getsetup", id => "tla", call => \&getsetup);
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+ hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit);
+ hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged);
+ hook(type => "rcs", id => "rcs_add", call => \&rcs_add);
+ hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove);
+ hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename);
+ hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges);
+ hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime);
+}
+
+sub checkconfig () {
+ if (defined $config{tla_wrapper} && length $config{tla_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{tla_wrapper},
+ wrappermode => (defined $config{tla_wrappermode} ? $config{tla_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # rcs plugin
+ rebuild => undef,
+ },
+ tla_wrapper => {
+ type => "string",
+ #example => "", # TODO example
+ description => "tla post-commit hook to generate",
+ safe => 0, # file
+ rebuild => 0,
+ },
+ tla_wrappermode => {
+ type => "string",
+ example => '06755',
+ description => "mode for tla_wrapper (can safely be made suid)",
+ safe => 0,
+ rebuild => 0,
+ },
+ historyurl => {
+ type => "string",
+ #example => "", # TODO example
+ description => "url to show file history ([[file]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+ diffurl => {
+ type => "string",
+ #example => "", # TODO example
+ description => "url to show a diff ([[file]] and [[rev]] substituted)",
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub quiet_system (@) {
+ # See Debian bug #385939.
+ open (SAVEOUT, ">&STDOUT");
+ close STDOUT;
+ open (STDOUT, ">/dev/null");
+ my $ret=system(@_);
+ close STDOUT;
+ open (STDOUT, ">&SAVEOUT");
+ close SAVEOUT;
+ return $ret;
+}
+
+sub rcs_update () {
+ if (-d "$config{srcdir}/{arch}") {
+ if (quiet_system("tla", "replay", "-d", $config{srcdir}) != 0) {
+ warn("tla replay failed\n");
+ }
+ }
+}
+
+sub rcs_prepedit ($) {
+ my $file=shift;
+
+ if (-d "$config{srcdir}/{arch}") {
+ # For Arch, return the tree-id of archive when
+ # editing begins.
+ my $rev=`tla tree-id $config{srcdir}`;
+ return defined $rev ? $rev : "";
+ }
+}
+
+sub rcs_commit ($$$;$$) {
+ my $file=shift;
+ my $message=shift;
+ my $rcstoken=shift;
+ my $user=shift;
+ my $ipaddr=shift;
+
+ if (defined $user) {
+ $message="web commit by $user".(length $message ? ": $message" : "");
+ }
+ elsif (defined $ipaddr) {
+ $message="web commit from $ipaddr".(length $message ? ": $message" : "");
+ }
+
+ if (-d "$config{srcdir}/{arch}") {
+ # Check to see if the page has been changed by someone
+ # else since rcs_prepedit was called.
+ my ($oldrev)=$rcstoken=~/^([A-Za-z0-9@\/._-]+)$/; # untaint
+ my $rev=`tla tree-id $config{srcdir}`;
+ if (defined $rev && defined $oldrev && $rev ne $oldrev) {
+ # Merge their changes into the file that we've
+ # changed.
+ if (quiet_system("tla", "update", "-d",
+ "$config{srcdir}") != 0) {
+ warn("tla update failed\n");
+ }
+ }
+
+ if (quiet_system("tla", "commit",
+ "-L".IkiWiki::possibly_foolish_untaint($message),
+ '-d', $config{srcdir}) != 0) {
+ my $conflict=readfile("$config{srcdir}/$file");
+ if (system("tla", "undo", "-n", "--quiet", "-d", "$config{srcdir}") != 0) {
+ warn("tla undo failed\n");
+ }
+ return $conflict;
+ }
+ }
+ return undef # success
+}
+
+sub rcs_commit_staged ($$$) {
+ # Commits all staged changes. Changes can be staged using rcs_add,
+ # rcs_remove, and rcs_rename.
+ my ($message, $user, $ipaddr)=@_;
+
+ error("rcs_commit_staged not implemented for tla"); # TODO
+}
+
+sub rcs_add ($) {
+ my $file=shift;
+
+ if (-d "$config{srcdir}/{arch}") {
+ if (quiet_system("tla", "add", "$config{srcdir}/$file") != 0) {
+ warn("tla add failed\n");
+ }
+ }
+}
+
+sub rcs_remove ($) {
+ my $file = shift;
+
+ error("rcs_remove not implemented for tla"); # TODO
+}
+
+sub rcs_rename ($$) { # {{{a
+ my ($src, $dest) = @_;
+
+ error("rcs_rename not implemented for tla"); # TODO
+}
+
+sub rcs_recentchanges ($) {
+ my $num=shift;
+ my @ret;
+
+ return unless -d "$config{srcdir}/{arch}";
+
+ eval q{use Date::Parse};
+ error($@) if $@;
+ eval q{use Mail::Header};
+ error($@) if $@;
+
+ my $logs = `tla logs -d $config{srcdir}`;
+ my @changesets = reverse split(/\n/, $logs);
+
+ for (my $i=0; $i<$num && $i<$#changesets; $i++) {
+ my ($change)=$changesets[$i]=~/^([A-Za-z0-9@\/._-]+)$/; # untaint
+
+ open(LOG, "tla cat-log -d $config{srcdir} $change|");
+ my $head = Mail::Header->new(\*LOG);
+ close(LOG);
+
+ my $rev = $head->get("Revision");
+ my $summ = $head->get("Summary");
+ my $newfiles = $head->get("New-files");
+ my $modfiles = $head->get("Modified-files");
+ my $remfiles = $head->get("Removed-files");
+ my $user = $head->get("Creator");
+
+ my @paths = grep { !/^(.*\/)?\.arch-ids\/.*\.id$/ }
+ split(/ /, "$newfiles $modfiles .arch-ids/fake.id");
+
+ my $sdate = $head->get("Standard-date");
+ my $when = str2time($sdate, 'UTC');
+
+ my $committype = "web";
+ if (defined $summ && $summ =~ /$config{web_commit_regexp}/) {
+ $user = defined $2 ? "$2" : "$3";
+ $summ = $4;
+ }
+ else {
+ $committype="tla";
+ }
+
+ my @message;
+ push @message, { line => $summ };
+
+ my @pages;
+
+ foreach my $file (@paths) {
+ my $diffurl=defined $config{diffurl} ? $config{diffurl} : "";
+ $diffurl=~s/\[\[file\]\]/$file/g;
+ $diffurl=~s/\[\[rev\]\]/$change/g;
+ push @pages, {
+ page => pagename($file),
+ diffurl => $diffurl,
+ } if length $file;
+ }
+ push @ret, {
+ rev => $change,
+ user => $user,
+ committype => $committype,
+ when => $when,
+ message => [@message],
+ pages => [@pages],
+ } if @pages;
+
+ last if $i == $num;
+ }
+
+ return @ret;
+}
+
+sub rcs_diff ($) {
+ my $rev=shift;
+ my $logs = `tla logs -d $config{srcdir}`;
+ my @changesets = reverse split(/\n/, $logs);
+ my $i;
+
+ for($i=0;$i<$#changesets;$i++) {
+ last if $changesets[$i] eq $rev;
+ }
+
+ my $revminusone = $changesets[$i+1];
+ return `tla diff -d $config{srcdir} $revminusone`;
+}
+
+sub rcs_getctime ($) {
+ my $file=shift;
+ eval q{use Date::Parse};
+ error($@) if $@;
+ eval q{use Mail::Header};
+ error($@) if $@;
+
+ my $logs = `tla logs -d $config{srcdir}`;
+ my @changesets = reverse split(/\n/, $logs);
+ my $sdate;
+
+ for (my $i=0; $i<$#changesets; $i++) {
+ my $change = $changesets[$i];
+
+ open(LOG, "tla cat-log -d $config{srcdir} $change|");
+ my $head = Mail::Header->new(\*LOG);
+ close(LOG);
+
+ $sdate = $head->get("Standard-date");
+ my $newfiles = $head->get("New-files");
+
+ my ($lastcreation) = grep {/^$file$/} split(/ /, "$newfiles");
+ last if defined($lastcreation);
+ }
+
+ my $date=str2time($sdate, 'UTC');
+ debug("found ctime ".localtime($date)." for $file");
+ return $date;
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use HTML::Parser;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "toc", call => \&getsetup);
hook(type => "preprocess", id => "toc", call => \&preprocess);
hook(type => "format", id => "toc", call => \&format);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
my %tocpages;
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
if ($params{page} eq $params{destpage}) {
# right.
return "";
}
-} # }}}
+}
-sub format (@) { #{{{
+sub format (@) {
my %params=@_;
my $content=$params{content};
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-# Here's the javascript that makes this possible. A key feature is the use
-# of css to hide toggleables, to avoid any flashing on page load. The css
-# is only emitted after the javascript tests that it's going to be able to
-# show the toggleables.
-our $javascript=<<'EOF';
-<script type="text/javascript">
-<!--
-if (document.getElementById && document.getElementsByTagName && document.createTextNode) {
- document.write('<style type="text/css">div.toggleable { display: none; }</style>');
- window.onload = inittoggle;
-}
-
-function inittoggle() {
- var as = getElementsByClass('toggle');
- for (var i = 0; i < as.length; i++) {
- var id = as[i].href.match(/#(\w.+)/)[1];
- if (document.getElementById(id).className == "toggleable")
- document.getElementById(id).style.display="none";
- as[i].onclick = function() {
- toggle(this);
- return false;
- }
- }
-}
-
-function toggle(s) {
- var id = s.href.match(/#(\w.+)/)[1];
- style = document.getElementById(id).style;
- if (style.display == "none")
- style.display = "block";
- else
- style.display = "none";
-}
-
-function getElementsByClass(class) {
- var ret = new Array();
- var pattern = new RegExp("(^|\\s)"+class+"(\\s|$)");
- var els = document.getElementsByTagName('*');
- for (i = 0, j = 0; i < els.length; i++) {
- if ( pattern.test(els[i].className) ) {
- ret[j] = els[i];
- j++;
- }
- }
- return ret;
-}
-//-->
-</script>
-EOF
-
-sub import { #{{{
+sub import {
+ add_underlay("javascript");
+ hook(type => "getsetup", id => "toggle", call => \&getsetup);
hook(type => "preprocess", id => "toggle",
call => \&preprocess_toggle);
hook(type => "preprocess", id => "toggleable",
call => \&preprocess_toggleable);
hook(type => "format", id => "toggle", call => \&format);
-} # }}}
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
-sub genid ($$) { #{{{
+sub genid ($$) {
my $page=shift;
my $id=shift;
$id="id$id";
}
return $id;
-} #}}}
+}
-sub preprocess_toggle (@) { #{{{
+sub preprocess_toggle (@) {
my %params=(id => "default", text => "more", @_);
my $id=genid($params{page}, $params{id});
return "<a class=\"toggle\" href=\"#$id\">$params{text}</a>";
-} # }}}
+}
-sub preprocess_toggleable (@) { #{{{
+sub preprocess_toggleable (@) {
my %params=(id => "default", text => "", open => "no", @_);
# Preprocess the text to expand any preprocessor directives
my ($indent)=$params{text}=~/( +)$/;
$indent="" unless defined $indent;
return "<div class=\"$class\" id=\"$id\"></div>\n\n$params{text}\n$indent<div class=\"toggleableend\"></div>";
-} # }}}
+}
-sub format (@) { #{{{
+sub format (@) {
my %params=@_;
- if ($params{content}=~s!(<div class="toggleable(?:-open)?" id="[^"]+">)</div>!$1!g) {
+ if ($params{content}=~s!(<div class="toggleable(?:-open)?" id="[^"]+">\s*)</div>!$1!g) {
$params{content}=~s/<div class="toggleableend">//g;
- if (! ($params{content}=~s!^<body>!<body>$javascript!m)) {
+ if (! ($params{content}=~s!^(<body>)!$1.include_javascript($params{page})!em)) {
# no </body> tag, probably in preview mode
- $params{content}=$javascript.$params{content};
+ $params{content}=include_javascript($params{page}, 1).$params{content};
}
}
return $params{content};
-} # }}}
+}
+
+sub include_javascript ($;$) {
+ my $page=shift;
+ my $absolute=shift;
+
+ return '<script src="'.urlto("ikiwiki.js", $page, $absolute).
+ '" type="text/javascript" charset="utf-8"></script>'."\n".
+ '<script src="'.urlto("toggle.js", $page, $absolute).
+ '" type="text/javascript" charset="utf-8"></script>';
+}
1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
use HTML::Entities;
my $findurl=0;
sub import {
- hook(type => "filter", id => "txt", call => \&filter);
+ hook(type => "getsetup", id => "txt", call => \&getsetup);
+ hook(type => "filter", id => "txt", call => \&filter);
hook(type => "htmlize", id => "txt", call => \&htmlize);
eval q{use URI::Find};
}
}
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+}
+
# We use filter to convert raw text to HTML
# (htmlize is called after other plugins insert HTML)
sub filter (@) {
my $content = $params{content};
if (defined $pagesources{$params{page}} && $pagesources{$params{page}} =~ /\.txt$/) {
- encode_entities($content);
+ encode_entities($content, "<>&");
if ($findurl) {
my $finder = URI::Find->new(sub {
my ($uri, $orig_uri) = @_;
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
hook(type => "getopt", id => "typography", call => \&getopt);
+ hook(type => "getsetup", id => "typography", call => \&getsetup);
IkiWiki::hook(type => "sanitize", id => "typography", call => \&sanitize);
-} # }}}
+}
-sub getopt () { #{{{
+sub getopt () {
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
GetOptions("typographyattributes=s" => \$config{typographyattributes});
-} #}}}
+}
-sub sanitize (@) { #{{{
+sub getsetup () {
+ eval q{use Text::Typography};
+ error($@) if $@;
+
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ typographyattributes => {
+ type => "string",
+ example => "3",
+ description => "Text::Typography attributes value",
+ advanced => 1,
+ safe => 1,
+ rebuild => 1,
+ },
+}
+
+sub sanitize (@) {
my %params=@_;
eval q{use Text::Typography};
- error($@) if $@;
+ return $params{content} if $@;
my $attributes=defined $config{typographyattributes} ? $config{typographyattributes} : '3';
return Text::Typography::typography($params{content}, $attributes);
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::underlay;
+# Copyright © 2008 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+# Licensed under the GNU GPL, version 2, or any later version published by the
+# Free Software Foundation
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getsetup", id => "underlay", call => \&getsetup);
+ hook(type => "checkconfig", id => "underlay", call => \&checkconfig);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0,
+ rebuild => undef,
+ },
+ add_underlays => {
+ type => "string",
+ default => [],
+ description => "extra underlay directories to add",
+ advanced => 1,
+ safe => 0,
+ rebuild => 1,
+ },
+}
+
+sub checkconfig () {
+ return unless exists $config{add_underlays};
+
+ foreach my $dir (@{$config{add_underlays}}) {
+ add_underlay($dir);
+ }
+}
+
+1;
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "version", call => \&getsetup);
hook(type => "needsbuild", id => "version", call => \&needsbuild);
hook(type => "preprocess", id => "version", call => \&preprocess);
-} # }}}
+}
-sub needsbuild (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+}
+
+sub needsbuild (@) {
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
if (exists $pagestate{$page}{version}{shown}) {
}
}
}
-} # }}}
+}
-sub preprocess (@) { #{{{
+sub preprocess (@) {
my %params=@_;
$pagestate{$params{destpage}}{version}{shown}=$IkiWiki::version;
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::websetup;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+ hook(type => "getsetup", id => "websetup", call => \&getsetup);
+ hook(type => "checkconfig", id => "websetup", call => \&checkconfig);
+ hook(type => "sessioncgi", id => "websetup", call => \&sessioncgi);
+ hook(type => "formbuilder_setup", id => "websetup",
+ call => \&formbuilder_setup);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 0,
+ },
+ websetup_force_plugins => {
+ type => "string",
+ example => [],
+ description => "list of plugins that cannot be enabled/disabled via the web interface",
+ safe => 0,
+ rebuild => 0,
+ },
+ websetup_show_unsafe => {
+ type => "boolean",
+ example => 1,
+ description => "show unsafe settings, read-only, in web interface?",
+ safe => 0,
+ rebuild => 0,
+ },
+}
+
+sub checkconfig () {
+ if (! exists $config{websetup_show_unsafe}) {
+ $config{websetup_show_unsafe}=1;
+ }
+}
+
+sub formatexample ($$) {
+ my $example=shift;
+ my $value=shift;
+
+ if (defined $value && length $value) {
+ return "";
+ }
+ elsif (defined $example && ! ref $example && length $example) {
+ return "<br/ ><small>Example: <tt>$example</tt></small>";
+ }
+ else {
+ return "";
+ }
+}
+
+sub showfields ($$$@) {
+ my $form=shift;
+ my $plugin=shift;
+ my $enabled=shift;
+
+ my @show;
+ my %plugininfo;
+ while (@_) {
+ my $key=shift;
+ my %info=%{shift()};
+
+ # skip internal settings
+ next if defined $info{type} && $info{type} eq "internal";
+ # XXX hashes not handled yet
+ next if ref $config{$key} && ref $config{$key} eq 'HASH' || ref $info{example} eq 'HASH';
+ # maybe skip unsafe settings
+ next if ! $info{safe} && ! ($config{websetup_show_unsafe} && $config{websetup_advanced});
+ # maybe skip advanced settings
+ next if $info{advanced} && ! $config{websetup_advanced};
+ # these are handled specially, so don't show
+ next if $key eq 'add_plugins' || $key eq 'disable_plugins';
+
+ if ($key eq 'plugin') {
+ %plugininfo=%info;
+ next;
+ }
+
+ push @show, $key, \%info;
+ }
+
+ my $section=defined $plugin ? $plugin." ".gettext("plugin") : "main";
+ my %enabledfields;
+ my $shownfields=0;
+
+ my $plugin_forced=defined $plugin && (! $plugininfo{safe} ||
+ (exists $config{websetup_force_plugins} && grep { $_ eq $plugin } @{$config{websetup_force_plugins}}));
+ if ($plugin_forced && ! $enabled) {
+ # plugin is forced disabled, so skip its settings
+ @show=();
+ }
+
+ # show plugin toggle
+ if (defined $plugin && (! $plugin_forced || $config{websetup_advanced})) {
+ my $name="enable.$plugin";
+ $form->field(
+ name => $name,
+ label => "",
+ type => "checkbox",
+ fieldset => $section,
+ options => [ [ 1 => sprintf(gettext("enable %s?"), $plugin) ]]
+ );
+ if (! $form->submitted) {
+ $form->field(name => $name, value => $enabled);
+ }
+ if ($plugin_forced) {
+ $form->field(name => $name, disabled => 1);
+ }
+ else {
+ $enabledfields{$name}=[$name, \%plugininfo];
+ }
+ }
+
+ # show plugin settings
+ while (@show) {
+ my $key=shift @show;
+ my %info=%{shift @show};
+
+ my $description=$info{description};
+ if (exists $info{link} && length $info{link}) {
+ if ($info{link} =~ /^\w+:\/\//) {
+ $description="<a href=\"$info{link}\">$description</a>";
+ }
+ else {
+ $description=htmllink("", "", $info{link}, noimageinline => 1, linktext => $description);
+ }
+ }
+
+ # multiple plugins can have the same field
+ my $name=defined $plugin ? $plugin.".".$key : $section.".".$key;
+
+ my $value=$config{$key};
+
+ if ($info{safe} && (ref $value eq 'ARRAY' || ref $info{example} eq 'ARRAY')) {
+ $value=[(ref $value eq 'ARRAY' ? @{$value} : ""), "", ""]; # blank items for expansion
+ }
+
+ if ($info{type} eq "string") {
+ $form->field(
+ name => $name,
+ label => $description,
+ comment => formatexample($info{example}, $value),
+ type => "text",
+ value => $value,
+ size => 60,
+ fieldset => $section,
+ );
+ }
+ elsif ($info{type} eq "pagespec") {
+ $form->field(
+ name => $name,
+ label => $description,
+ comment => formatexample($info{example}, $value),
+ type => "text",
+ value => $value,
+ size => 60,
+ validate => \&IkiWiki::pagespec_valid,
+ fieldset => $section,
+ );
+ }
+ elsif ($info{type} eq "integer") {
+ $form->field(
+ name => $name,
+ label => $description,
+ comment => formatexample($info{example}, $value),
+ type => "text",
+ value => $value,
+ size => 5,
+ validate => '/^[0-9]+$/',
+ fieldset => $section,
+ );
+ }
+ elsif ($info{type} eq "boolean") {
+ $form->field(
+ name => $name,
+ label => "",
+ type => "checkbox",
+ options => [ [ 1 => $description ] ],
+ fieldset => $section,
+ );
+ if (! $form->submitted) {
+ $form->field(name => $name, value => $value);
+ }
+ }
+
+ if (! $info{safe}) {
+ $form->field(name => $name, disabled => 1);
+ }
+ else {
+ $enabledfields{$name}=[$key, \%info];
+ }
+ $shownfields++;
+ }
+
+ # if no fields were shown for the plugin, drop it into the
+ # plugins fieldset
+ if (defined $plugin && (! $plugin_forced || $config{websetup_advanced}) &&
+ ! $shownfields) {
+ $form->field(name => "enable.$plugin", fieldset => "plugins");
+ }
+
+ return %enabledfields;
+}
+
+sub enable_plugin ($) {
+ my $plugin=shift;
+
+ $config{disable_plugins}=[grep { $_ ne $plugin } @{$config{disable_plugins}}];
+ push @{$config{add_plugins}}, $plugin;
+}
+
+sub disable_plugin ($) {
+ my $plugin=shift;
+
+ if (grep { $_ eq $plugin } @{$config{add_plugins}}) {
+ $config{add_plugins}=[grep { $_ ne $plugin } @{$config{add_plugins}}];
+ }
+ else {
+ push @{$config{disable_plugins}}, $plugin;
+ }
+}
+
+sub showform ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ if (! defined $session->param("name") ||
+ ! IkiWiki::is_admin($session->param("name"))) {
+ error(gettext("you are not logged in as an admin"));
+ }
+
+ if (! exists $config{setupfile}) {
+ error(gettext("setup file for this wiki is not known"));
+ }
+
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+
+ my $form = CGI::FormBuilder->new(
+ title => "setup",
+ name => "setup",
+ header => 0,
+ charset => "utf-8",
+ method => 'POST',
+ javascript => 0,
+ reset => 1,
+ params => $cgi,
+ fieldsets => [
+ [main => gettext("main")],
+ [plugins => gettext("plugins")]
+ ],
+ action => $config{cgiurl},
+ template => {type => 'div'},
+ stylesheet => IkiWiki::baseurl()."style.css",
+ );
+
+ $form->field(name => "do", type => "hidden", value => "setup",
+ force => 1);
+ $form->field(name => "rebuild_asked", type => "hidden");
+
+ if ($form->submitted eq 'Basic Mode') {
+ $form->field(name => "showadvanced", type => "hidden",
+ value => 0, force => 1);
+ }
+ elsif ($form->submitted eq 'Advanced Mode') {
+ $form->field(name => "showadvanced", type => "hidden",
+ value => 1, force => 1);
+ }
+ my $advancedtoggle;
+ if ($form->field("showadvanced")) {
+ $config{websetup_advanced}=1;
+ $advancedtoggle="Basic Mode";
+ }
+ else {
+ $config{websetup_advanced}=0;
+ $advancedtoggle="Advanced Mode";
+ }
+
+ my $buttons=["Save Setup", $advancedtoggle, "Cancel"];
+
+ IkiWiki::decode_form_utf8($form);
+ IkiWiki::run_hooks(formbuilder_setup => sub {
+ shift->(form => $form, cgi => $cgi, session => $session,
+ buttons => $buttons);
+ });
+ IkiWiki::decode_form_utf8($form);
+
+ my %fields=showfields($form, undef, undef, IkiWiki::getsetup());
+
+ # record all currently enabled plugins before all are loaded
+ my %enabled_plugins=%IkiWiki::loaded_plugins;
+
+ # per-plugin setup
+ require IkiWiki::Setup;
+ foreach my $pair (IkiWiki::Setup::getsetup()) {
+ my $plugin=$pair->[0];
+ my $setup=$pair->[1];
+
+ my %shown=showfields($form, $plugin, $enabled_plugins{$plugin}, @{$setup});
+ if (%shown) {
+ $fields{$_}=$shown{$_} foreach keys %shown;
+ }
+ }
+
+ if ($form->submitted eq "Cancel") {
+ IkiWiki::redirect($cgi, $config{url});
+ return;
+ }
+ elsif (($form->submitted eq 'Save Setup' || $form->submitted eq 'Rebuild Wiki') && $form->validate) {
+ # Push values from form into %config, avoiding unnecessary
+ # changes, and keeping track of which changes need a
+ # rebuild.
+ my %rebuild;
+ foreach my $field (keys %fields) {
+ my %info=%{$fields{$field}->[1]};
+ my $key=$fields{$field}->[0];
+ my @value=$form->field($field);
+ if (! @value) {
+ @value=0;
+ }
+
+ if (! $info{safe}) {
+ error("unsafe field $key"); # should never happen
+ }
+
+ if (exists $info{rebuild} &&
+ ($info{rebuild} || ! defined $info{rebuild})) {
+ $rebuild{$field}=$info{rebuild};
+ }
+
+ if ($field=~/^enable\.(.*)/) {
+ my $plugin=$1;
+ $value[0]=0 if ! length $value[0];
+ if ($value[0] != exists $enabled_plugins{$plugin}) {
+ if ($value[0]) {
+ enable_plugin($plugin);
+ }
+ else {
+ disable_plugin($plugin);
+
+ }
+ }
+ else {
+ delete $rebuild{$field};
+ }
+ next;
+ }
+
+ if (ref $config{$key} eq "ARRAY" || ref $info{example} eq "ARRAY") {
+ @value=sort grep { length $_ } @value;
+ my @oldvalue=sort grep { length $_ }
+ (defined $config{$key} ? @{$config{$key}} : ());
+ if ((@oldvalue) == (@value)) {
+ delete $rebuild{$field};
+ }
+ else {
+ $config{$key}=\@value;
+ }
+ }
+ elsif (ref $config{$key} || ref $info{example}) {
+ error("complex field $key"); # should never happen
+ }
+ else {
+ if (defined $config{$key} && $config{$key} eq $value[0]) {
+ delete $rebuild{$field};
+ }
+ elsif (! defined $config{$key} && ! length $value[0]) {
+ delete $rebuild{$field};
+ }
+ elsif ((! defined $config{$key} || ! $config{$key}) &&
+ ! $value[0] && $info{type} eq "boolean") {
+ delete $rebuild{$field};
+ }
+ else {
+ $config{$key}=$value[0];
+ }
+ }
+ }
+
+ if (%rebuild && ! $form->field("rebuild_asked")) {
+ my $required=0;
+ foreach my $field ($form->field) {
+ $required=1 if $rebuild{$field};
+ next if exists $rebuild{$field};
+ $form->field(name => $field, type => "hidden");
+ }
+ if ($required) {
+ $form->text(gettext("The configuration changes shown below require a wiki rebuild to take effect."));
+ $buttons=["Rebuild Wiki", "Cancel"];
+ }
+ else {
+ $form->text(gettext("For the configuration changes shown below to fully take effect, you may need to rebuild the wiki."));
+ $buttons=["Rebuild Wiki", "Save Setup", "Cancel"];
+ }
+ $form->field(name => "rebuild_asked", value => 1, force => 1);
+ $form->reset(0); # doesn't really make sense here
+ }
+ else {
+ my $oldsetup=readfile($config{setupfile});
+ IkiWiki::Setup::dump($config{setupfile});
+
+ IkiWiki::saveindex();
+ IkiWiki::unlockwiki();
+
+ # Print the top part of a standard misctemplate,
+ # then show the rebuild or refresh.
+ my $divider="xxx";
+ my $html=IkiWiki::misctemplate("setup", $divider);
+ IkiWiki::printheader($session);
+ my ($head, $tail)=split($divider, $html, 2);
+ print $head."<pre>\n";
+
+ my @command;
+ if ($form->submitted eq 'Rebuild Wiki') {
+ @command=("ikiwiki", "-setup", $config{setupfile},
+ "-rebuild", "-v");
+ }
+ else {
+ @command=("ikiwiki", "-setup", $config{setupfile},
+ "-refresh", "-wrappers", "-v");
+ }
+
+ close STDERR;
+ open(STDERR, ">&STDOUT");
+ my $ret=system(@command);
+ print "\n<\/pre>";
+ if ($ret != 0) {
+ print '<p class="error">'.
+ sprintf(gettext("Error: %s exited nonzero (%s). Discarding setup changes."),
+ join(" ", @command), $ret).
+ '</p>';
+ open(OUT, ">", $config{setupfile}) || error("$config{setupfile}: $!");
+ print OUT $oldsetup;
+ close OUT;
+ }
+
+ print $tail;
+ exit 0;
+ }
+ }
+
+ IkiWiki::showform($form, $buttons, $session, $cgi);
+}
+
+sub sessioncgi ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ if ($cgi->param("do") eq "setup") {
+ showform($cgi, $session);
+ exit;
+ }
+}
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+
+ my $form=$params{form};
+ if ($form->title eq "preferences") {
+ push @{$params{buttons}}, "Wiki Setup";
+ if ($form->submitted && $form->submitted eq "Wiki Setup") {
+ showform($params{cgi}, $params{session});
+ exit;
+ }
+ }
+}
+
+1
use warnings;
use strict;
-use IkiWiki 2.00;
+use IkiWiki 3.00;
-sub import { #{{{
+sub import {
+ hook(type => "getsetup", id => "wiki", call => \&getsetup);
hook(type => "htmlize", id => "wiki", call => \&htmlize);
-} # }}}
+}
-sub htmlize (@) { #{{{
+sub getsetup () {
+ return
+ plugin => {
+ safe => 0, # format plugin
+ rebuild => undef,
+ },
+}
+
+
+sub htmlize (@) {
my %params=@_;
my $content = $params{content};
eval q{use Text::WikiFormat};
return $content if $@;
return Text::WikiFormat::format($content, undef, { implicit_links => 0 });
-} # }}}
+}
1
--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::wmd;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+use POSIX;
+use Encode;
+
+sub import {
+ add_underlay("wmd");
+ hook(type => "getsetup", id => "wmd", call => \&getsetup);
+ hook(type => "formbuilder_setup", id => "wmd", call => \&formbuilder_setup);
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ },
+}
+
+sub formbuilder_setup (@) {
+ my %params=@_;
+ my $form=$params{form};
+
+ return if ! defined $form->field("do");
+
+ return unless $form->field("do") eq "edit" ||
+ $form->field("do") eq "create" ||
+ $form->field("do") eq "comment";
+
+ $form->tmpl_param("wmd_preview", "<div class=\"wmd-preview\"></div>\n".
+ include_javascript(undef, 1));
+}
+
+sub include_javascript ($;$) {
+ my $page=shift;
+ my $absolute=shift;
+
+ my $wmdjs=urlto("wmd/wmd.js", $page, $absolute);
+ return <<"EOF"
+<script type="text/javascript">
+wmd_options = {
+ output: "Markdown"
+};
+</script>
+<script src="$wmdjs" type="text/javascript"></script>
+EOF
+}
+
+1
+++ /dev/null
-#!/usr/bin/perl
-# Stubs for no revision control.
-
-use warnings;
-use strict;
-use IkiWiki;
-
-package IkiWiki;
-
-sub rcs_update () {
- # Update working directory to current version.
- # (May be more complex for distributed RCS.)
-}
-
-sub rcs_prepedit ($) {
- # Prepares to edit a file under revision control. Returns a token
- # that must be passed into rcs_commit when the file is ready
- # for committing.
- # The file is relative to the srcdir.
- return ""
-}
-
-sub rcs_commit ($$$;$$) {
- # Tries to commit the page; returns undef on _success_ and
- # a version of the page with the rcs's conflict markers on failure.
- # The file is relative to the srcdir.
- return undef # success
-}
-
-sub rcs_add ($) {
- # Add a file. The filename is relative to the root of the srcdir.
- # Note that this should not check the new file in, it should only
- # prepare for it to be checked in when rcs_commit is called.
-}
-
-sub rcs_recentchanges ($) {
- # Examine the RCS history and generate a list of recent changes.
- # The data structure returned for each change is:
- # {
- # rev => # the RCSs id for this commit
- # user => # name of user who made the change,
- # committype => # either "web" or the name of the rcs,
- # when => # time when the change was made,
- # message => [
- # { line => "commit message line" },
- # { line => "commit message line" },
- # # etc,
- # ],
- # pages => [
- # {
- # page => # name of page changed,
- # diffurl => # optional url to a diff showing
- # # the changes,
- # },
- # # repeat for each page changed in this commit,
- # ],
- # }
-}
-
-sub rcs_diff ($) {
- # Optional, used to get diffs for recentchanges.
- # The parameter is the rev from rcs_recentchanges.
- # Should return a list of lines of the diff (including \n) in list
- # context, and the whole diff in scalar context.
-}
-
-sub rcs_getctime ($) {
- # Optional, used to get the page creation time from the RCS.
- error gettext("getctime not implemented");
-}
-
-1
+++ /dev/null
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use IkiWiki;
-use Encode;
-use open qw{:utf8 :std};
-
-package IkiWiki;
-
-sub bzr_log ($) { #{{{
- my $out = shift;
- my @infos = ();
- my $key = undef;
-
- while (<$out>) {
- my $line = $_;
- my ($value);
- if ($line =~ /^message:/) {
- $key = "message";
- $infos[$#infos]{$key} = "";
- }
- elsif ($line =~ /^(modified|added|renamed|renamed and modified|removed):/) {
- $key = "files";
- unless (defined($infos[$#infos]{$key})) { $infos[$#infos]{$key} = ""; }
- }
- elsif (defined($key) and $line =~ /^ (.*)/) {
- $infos[$#infos]{$key} .= $1;
- }
- elsif ($line eq "------------------------------------------------------------\n") {
- $key = undef;
- push (@infos, {});
- }
- else {
- chomp $line;
- ($key, $value) = split /: +/, $line, 2;
- $infos[$#infos]{$key} = $value;
- }
- }
- close $out;
-
- return @infos;
-} #}}}
-
-sub rcs_update () { #{{{
- my @cmdline = ("bzr", "update", "--quiet", $config{srcdir});
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
-} #}}}
-
-sub rcs_prepedit ($) { #{{{
- return "";
-} #}}}
-
-sub rcs_commit ($$$;$$) { #{{{
- my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
-
- if (defined $user) {
- $user = possibly_foolish_untaint($user);
- }
- elsif (defined $ipaddr) {
- $user = "Anonymous from ".possibly_foolish_untaint($ipaddr);
- }
- else {
- $user = "Anonymous";
- }
-
- $message = possibly_foolish_untaint($message);
- if (! length $message) {
- $message = "no message given";
- }
-
- my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
- $config{srcdir}."/".$file);
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
-
- return undef; # success
-} #}}}
-
-sub rcs_add ($) { # {{{
- my ($file) = @_;
-
- my @cmdline = ("bzr", "add", "--quiet", "$config{srcdir}/$file");
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
-} #}}}
-
-sub rcs_recentchanges ($) { #{{{
- my ($num) = @_;
-
- my @cmdline = ("bzr", "log", "-v", "--show-ids", "--limit", $num,
- $config{srcdir});
- open (my $out, "@cmdline |");
-
- eval q{use Date::Parse};
- error($@) if $@;
-
- my @ret;
- foreach my $info (bzr_log($out)) {
- my @pages = ();
- my @message = ();
-
- foreach my $msgline (split(/\n/, $info->{message})) {
- push @message, { line => $msgline };
- }
-
- foreach my $file (split(/\n/, $info->{files})) {
- my ($filename, $fileid) = split(/[ \t]+/, $file);
- my $diffurl = $config{'diffurl'};
- $diffurl =~ s/\[\[file\]\]/$filename/go;
- $diffurl =~ s/\[\[file-id\]\]/$fileid/go;
- $diffurl =~ s/\[\[r2\]\]/$info->{revno}/go;
-
- push @pages, {
- page => pagename($filename),
- diffurl => $diffurl,
- };
- }
-
- my $user = $info->{"committer"};
- if (defined($info->{"author"})) { $user = $info->{"author"}; }
- $user =~ s/\s*<.*>\s*$//;
- $user =~ s/^\s*//;
-
- push @ret, {
- rev => $info->{"revno"},
- user => $user,
- committype => "bzr",
- when => time - str2time($info->{"timestamp"}),
- message => [@message],
- pages => [@pages],
- };
- }
-
- return @ret;
-} #}}}
-
-sub rcs_getctime ($) { #{{{
- my ($file) = @_;
-
- # XXX filename passes through the shell here, should try to avoid
- # that just in case
- my @cmdline = ("bzr", "log", "--limit", '1', "$config{srcdir}/$file");
- open (my $out, "@cmdline |");
-
- my @log = bzr_log($out);
-
- if (length @log < 1) {
- return 0;
- }
-
- eval q{use Date::Parse};
- error($@) if $@;
-
- my $ctime = str2time($log[0]->{"timestamp"});
- return $ctime;
-} #}}}
-
-1
+++ /dev/null
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use IkiWiki;
-use Encode;
-use open qw{:utf8 :std};
-
-package IkiWiki;
-
-my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums
-my $dummy_commit_msg = 'dummy commit'; # message to skip in recent changes
-
-sub _safe_git (&@) { #{{{
- # Start a child process safely without resorting /bin/sh.
- # Return command output or success state (in scalar context).
-
- my ($error_handler, @cmdline) = @_;
-
- my $pid = open my $OUT, "-|";
-
- error("Cannot fork: $!") if !defined $pid;
-
- if (!$pid) {
- # In child.
- # Git commands want to be in wc.
- chdir $config{srcdir}
- or error("Cannot chdir to $config{srcdir}: $!");
- exec @cmdline or error("Cannot exec '@cmdline': $!");
- }
- # In parent.
-
- my @lines;
- while (<$OUT>) {
- chomp;
- push @lines, $_;
- }
-
- close $OUT;
-
- $error_handler->("'@cmdline' failed: $!") if $? && $error_handler;
-
- return wantarray ? @lines : ($? == 0);
-}
-# Convenient wrappers.
-sub run_or_die ($@) { _safe_git(\&error, @_) }
-sub run_or_cry ($@) { _safe_git(sub { warn @_ }, @_) }
-sub run_or_non ($@) { _safe_git(undef, @_) }
-#}}}
-
-sub _merge_past ($$$) { #{{{
- # Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'.
- # Git merge commands work with the committed changes, except in the
- # implicit case of '-m' of git checkout(1). So we should invent a
- # kludge here. In principle, we need to create a throw-away branch
- # in preparing for the merge itself. Since branches are cheap (and
- # branching is fast), this shouldn't cost high.
- #
- # The main problem is the presence of _uncommitted_ local changes. One
- # possible approach to get rid of this situation could be that we first
- # make a temporary commit in the master branch and later restore the
- # initial state (this is possible since Git has the ability to undo a
- # commit, i.e. 'git reset --soft HEAD^'). The method can be summarized
- # as follows:
- #
- # - create a diff of HEAD:current-sha1
- # - dummy commit
- # - create a dummy branch and switch to it
- # - rewind to past (reset --hard to the current-sha1)
- # - apply the diff and commit
- # - switch to master and do the merge with the dummy branch
- # - make a soft reset (undo the last commit of master)
- #
- # The above method has some drawbacks: (1) it needs a redundant commit
- # just to get rid of local changes, (2) somewhat slow because of the
- # required system forks. Until someone points a more straight method
- # (which I would be grateful) I have implemented an alternative method.
- # In this approach, we hide all the modified files from Git by renaming
- # them (using the 'rename' builtin) and later restore those files in
- # the throw-away branch (that is, we put the files themselves instead
- # of applying a patch).
-
- my ($sha1, $file, $message) = @_;
-
- my @undo; # undo stack for cleanup in case of an error
- my $conflict; # file content with conflict markers
-
- eval {
- # Hide local changes from Git by renaming the modified file.
- # Relative paths must be converted to absolute for renaming.
- my ($target, $hidden) = (
- "$config{srcdir}/${file}", "$config{srcdir}/${file}.${sha1}"
- );
- rename($target, $hidden)
- or error("rename '$target' to '$hidden' failed: $!");
- # Ensure to restore the renamed file on error.
- push @undo, sub {
- return if ! -e "$hidden"; # already renamed
- rename($hidden, $target)
- or warn "rename '$hidden' to '$target' failed: $!";
- };
-
- my $branch = "throw_away_${sha1}"; # supposed to be unique
-
- # Create a throw-away branch and rewind backward.
- push @undo, sub { run_or_cry('git', 'branch', '-D', $branch) };
- run_or_die('git', 'branch', $branch, $sha1);
-
- # Switch to throw-away branch for the merge operation.
- push @undo, sub {
- if (!run_or_cry('git', 'checkout', $config{gitmaster_branch})) {
- run_or_cry('git', 'checkout','-f',$config{gitmaster_branch});
- }
- };
- run_or_die('git', 'checkout', $branch);
-
- # Put the modified file in _this_ branch.
- rename($hidden, $target)
- or error("rename '$hidden' to '$target' failed: $!");
-
- # _Silently_ commit all modifications in the current branch.
- run_or_non('git', 'commit', '-m', $message, '-a');
- # ... and re-switch to master.
- run_or_die('git', 'checkout', $config{gitmaster_branch});
-
- # Attempt to merge without complaining.
- if (!run_or_non('git', 'pull', '--no-commit', '.', $branch)) {
- $conflict = readfile($target);
- run_or_die('git', 'reset', '--hard');
- }
- };
- my $failure = $@;
-
- # Process undo stack (in reverse order). By policy cleanup
- # actions should normally print a warning on failure.
- while (my $handle = pop @undo) {
- $handle->();
- }
-
- error("Git merge failed!\n$failure\n") if $failure;
-
- return $conflict;
-} #}}}
-
-sub _parse_diff_tree ($@) { #{{{
- # Parse the raw diff tree chunk and return the info hash.
- # See git-diff-tree(1) for the syntax.
-
- my ($prefix, $dt_ref) = @_;
-
- # End of stream?
- return if !defined @{ $dt_ref } ||
- !defined @{ $dt_ref }[0] || !length @{ $dt_ref }[0];
-
- my %ci;
- # Header line.
- while (my $line = shift @{ $dt_ref }) {
- return if $line !~ m/^(.+) ($sha1_pattern)/;
-
- my $sha1 = $2;
- $ci{'sha1'} = $sha1;
- last;
- }
-
- # Identification lines for the commit.
- while (my $line = shift @{ $dt_ref }) {
- # Regexps are semi-stolen from gitweb.cgi.
- if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) {
- $ci{'tree'} = $1;
- }
- elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) {
- # XXX: collecting in reverse order
- push @{ $ci{'parents'} }, $1;
- }
- elsif ($line =~ m/^(author|committer) (.*) ([0-9]+) (.*)$/) {
- my ($who, $name, $epoch, $tz) =
- ($1, $2, $3, $4 );
-
- $ci{ $who } = $name;
- $ci{ "${who}_epoch" } = $epoch;
- $ci{ "${who}_tz" } = $tz;
-
- if ($name =~ m/^([^<]+) <([^@>]+)/) {
- my ($fullname, $username) = ($1, $2);
- $ci{"${who}_fullname"} = $fullname;
- $ci{"${who}_username"} = $username;
- }
- else {
- $ci{"${who}_fullname"} =
- $ci{"${who}_username"} = $name;
- }
- }
- elsif ($line =~ m/^$/) {
- # Trailing empty line signals next section.
- last;
- }
- }
-
- debug("No 'tree' seen in diff-tree output") if !defined $ci{'tree'};
-
- if (defined $ci{'parents'}) {
- $ci{'parent'} = @{ $ci{'parents'} }[0];
- }
- else {
- $ci{'parent'} = 0 x 40;
- }
-
- # Commit message.
- while (my $line = shift @{ $dt_ref }) {
- if ($line =~ m/^$/) {
- # Trailing empty line signals next section.
- last;
- };
- $line =~ s/^ //;
- push @{ $ci{'comment'} }, $line;
- }
-
- # Modified files.
- while (my $line = shift @{ $dt_ref }) {
- if ($line =~ m{^
- (:+) # number of parents
- ([^\t]+)\t # modes, sha1, status
- (.*) # file names
- $}xo) {
- my $num_parents = length $1;
- my @tmp = split(" ", $2);
- my ($file, $file_to) = split("\t", $3);
- my @mode_from = splice(@tmp, 0, $num_parents);
- my $mode_to = shift(@tmp);
- my @sha1_from = splice(@tmp, 0, $num_parents);
- my $sha1_to = shift(@tmp);
- my $status = shift(@tmp);
-
- if ($file =~ m/^"(.*)"$/) {
- ($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg;
- }
- $file =~ s/^\Q$prefix\E//;
- if (length $file) {
- push @{ $ci{'details'} }, {
- 'file' => decode_utf8($file),
- 'sha1_from' => $sha1_from[0],
- 'sha1_to' => $sha1_to,
- };
- }
- next;
- };
- last;
- }
-
- return \%ci;
-} #}}}
-
-sub git_commit_info ($;$) { #{{{
- # Return an array of commit info hashes of num commits (default: 1)
- # starting from the given sha1sum.
-
- my ($sha1, $num) = @_;
-
- $num ||= 1;
-
- my @raw_lines = run_or_die('git', 'log', "--max-count=$num",
- '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c',
- '-r', $sha1, '--', '.');
- my ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix');
-
- my @ci;
- while (my $parsed = _parse_diff_tree(($prefix or ""), \@raw_lines)) {
- push @ci, $parsed;
- }
-
- warn "Cannot parse commit info for '$sha1' commit" if !@ci;
-
- return wantarray ? @ci : $ci[0];
-} #}}}
-
-sub git_sha1 (;$) { #{{{
- # Return head sha1sum (of given file).
-
- my $file = shift || q{--};
-
- # Ignore error since a non-existing file might be given.
- my ($sha1) = run_or_non('git', 'rev-list', '--max-count=1', 'HEAD',
- '--', $file);
- if ($sha1) {
- ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now
- } else { debug("Empty sha1sum for '$file'.") }
- return defined $sha1 ? $sha1 : q{};
-} #}}}
-
-sub rcs_update () { #{{{
- # Update working directory.
-
- if (length $config{gitorigin_branch}) {
- run_or_cry('git', 'pull', $config{gitorigin_branch});
- }
-} #}}}
-
-sub rcs_prepedit ($) { #{{{
- # Return the commit sha1sum of the file when editing begins.
- # This will be later used in rcs_commit if a merge is required.
-
- my ($file) = @_;
-
- return git_sha1($file);
-} #}}}
-
-sub rcs_commit ($$$;$$) { #{{{
- # Try to commit the page; returns undef on _success_ and
- # a version of the page with the rcs's conflict markers on
- # failure.
-
- my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
-
- if (defined $user) {
- $message = "web commit by $user" .
- (length $message ? ": $message" : "");
- }
- elsif (defined $ipaddr) {
- $message = "web commit from $ipaddr" .
- (length $message ? ": $message" : "");
- }
-
- # Check to see if the page has been changed by someone else since
- # rcs_prepedit was called.
- my $cur = git_sha1($file);
- my ($prev) = $rcstoken =~ /^($sha1_pattern)$/; # untaint
-
- if (defined $cur && defined $prev && $cur ne $prev) {
- my $conflict = _merge_past($prev, $file, $dummy_commit_msg);
- return $conflict if defined $conflict;
- }
-
- # git commit returns non-zero if file has not been really changed.
- # so we should ignore its exit status (hence run_or_non).
- $message = possibly_foolish_untaint($message);
- if (run_or_non('git', 'commit', '-q', '-m', $message, '-i', $file)) {
- if (length $config{gitorigin_branch}) {
- run_or_cry('git', 'push', $config{gitorigin_branch});
- }
- }
-
- return undef; # success
-} #}}}
-
-sub rcs_add ($) { # {{{
- # Add file to archive.
-
- my ($file) = @_;
-
- run_or_cry('git', 'add', $file);
-} #}}}
-
-sub rcs_recentchanges ($) { #{{{
- # List of recent changes.
-
- my ($num) = @_;
-
- eval q{use Date::Parse};
- error($@) if $@;
-
- my @rets;
- foreach my $ci (git_commit_info('HEAD', $num)) {
- # Skip redundant commits.
- next if (@{$ci->{'comment'}}[0] eq $dummy_commit_msg);
-
- my ($sha1, $when) = (
- $ci->{'sha1'},
- $ci->{'author_epoch'}
- );
-
- my (@pages, @messages);
- foreach my $detail (@{ $ci->{'details'} }) {
- my $file = $detail->{'file'};
-
- my $diffurl = $config{'diffurl'};
- $diffurl =~ s/\[\[file\]\]/$file/go;
- $diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go;
- $diffurl =~ s/\[\[sha1_from\]\]/$detail->{'sha1_from'}/go;
- $diffurl =~ s/\[\[sha1_to\]\]/$detail->{'sha1_to'}/go;
-
- push @pages, {
- page => pagename($file),
- diffurl => $diffurl,
- };
- }
-
- push @messages, { line => $_ } foreach grep {
- ! m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i
- } @{$ci->{'comment'}};
-
- my ($user, $type) = (q{}, "web");
-
- if (defined $messages[0] &&
- $messages[0]->{line} =~ m/$config{web_commit_regexp}/) {
- $user = defined $2 ? "$2" : "$3";
- $messages[0]->{line} = $4;
- }
- else {
- $type ="git";
- $user = $ci->{'author_username'};
- }
-
- push @rets, {
- rev => $sha1,
- user => $user,
- committype => $type,
- when => $when,
- message => [@messages],
- pages => [@pages],
- } if @pages;
-
- last if @rets >= $num;
- }
-
- return @rets;
-} #}}}
-
-sub rcs_diff ($) { #{{{
- my $rev=shift;
- my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint
- my @lines;
- foreach my $line (run_or_non("git", "show", $sha1)) {
- if (@lines || $line=~/^diff --git/) {
- push @lines, $line."\n";
- }
- }
- if (wantarray) {
- return @lines;
- }
- else {
- return join("", @lines);
- }
-} #}}}
-
-sub rcs_getctime ($) { #{{{
- my $file=shift;
- # Remove srcdir prefix
- $file =~ s/^\Q$config{srcdir}\E\/?//;
-
- my $sha1 = git_sha1($file);
- my $ci = git_commit_info($sha1);
- my $ctime = $ci->{'author_epoch'};
- debug("ctime for '$file': ". localtime($ctime));
-
- return $ctime;
-} #}}}
-
-1
+++ /dev/null
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use IkiWiki;
-use Encode;
-use open qw{:utf8 :std};
-
-package IkiWiki;
-
-sub mercurial_log($) {
- my $out = shift;
- my @infos;
-
- while (<$out>) {
- my $line = $_;
- my ($key, $value);
-
- if (/^description:/) {
- $key = "description";
- $value = "";
-
- # slurp everything as the description text
- # until the next changeset
- while (<$out>) {
- if (/^changeset: /) {
- $line = $_;
- last;
- }
-
- $value .= $_;
- }
-
- local $/ = "";
- chomp $value;
- $infos[$#infos]{$key} = $value;
- }
-
- chomp $line;
- ($key, $value) = split /: +/, $line, 2;
-
- if ($key eq "changeset") {
- push @infos, {};
-
- # remove the revision index, which is strictly
- # local to the repository
- $value =~ s/^\d+://;
- }
-
- $infos[$#infos]{$key} = $value;
- }
- close $out;
-
- return @infos;
-}
-
-sub rcs_update () { #{{{
- my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update");
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
-} #}}}
-
-sub rcs_prepedit ($) { #{{{
- return "";
-} #}}}
-
-sub rcs_commit ($$$;$$) { #{{{
- my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
-
- if (defined $user) {
- $user = possibly_foolish_untaint($user);
- }
- elsif (defined $ipaddr) {
- $user = "Anonymous from ".possibly_foolish_untaint($ipaddr);
- }
- else {
- $user = "Anonymous";
- }
-
- $message = possibly_foolish_untaint($message);
- if (! length $message) {
- $message = "no message given";
- }
-
- my @cmdline = ("hg", "-q", "-R", $config{srcdir}, "commit",
- "-m", $message, "-u", $user);
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
-
- return undef; # success
-} #}}}
-
-sub rcs_add ($) { # {{{
- my ($file) = @_;
-
- my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "add", "$config{srcdir}/$file");
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
-} #}}}
-
-sub rcs_recentchanges ($) { #{{{
- my ($num) = @_;
-
- my @cmdline = ("hg", "-R", $config{srcdir}, "log", "-v", "-l", $num,
- "--style", "default");
- open (my $out, "@cmdline |");
-
- eval q{use Date::Parse};
- error($@) if $@;
-
- my @ret;
- foreach my $info (mercurial_log($out)) {
- my @pages = ();
- my @message = ();
-
- foreach my $msgline (split(/\n/, $info->{description})) {
- push @message, { line => $msgline };
- }
-
- foreach my $file (split / /,$info->{files}) {
- my $diffurl = $config{'diffurl'};
- $diffurl =~ s/\[\[file\]\]/$file/go;
- $diffurl =~ s/\[\[r2\]\]/$info->{changeset}/go;
-
- push @pages, {
- page => pagename($file),
- diffurl => $diffurl,
- };
- }
-
- my $user = $info->{"user"};
- $user =~ s/\s*<.*>\s*$//;
- $user =~ s/^\s*//;
-
- push @ret, {
- rev => $info->{"changeset"},
- user => $user,
- committype => "mercurial",
- when => str2time($info->{"date"}),
- message => [@message],
- pages => [@pages],
- };
- }
-
- return @ret;
-} #}}}
-
-sub rcs_diff ($) { #{{{
- # TODO
-} #}}}
-
-sub rcs_getctime ($) { #{{{
- my ($file) = @_;
-
- # XXX filename passes through the shell here, should try to avoid
- # that just in case
- my @cmdline = ("hg", "-R", $config{srcdir}, "log", "-v", "-l", '1',
- "--style", "default", "$config{srcdir}/$file");
- open (my $out, "@cmdline |");
-
- my @log = mercurial_log($out);
-
- if (length @log < 1) {
- return 0;
- }
-
- eval q{use Date::Parse};
- error($@) if $@;
-
- my $ctime = str2time($log[0]->{"date"});
- return $ctime;
-} #}}}
-
-1
+++ /dev/null
-#!/usr/bin/perl
-use warnings;
-use strict;
-use IkiWiki;
-use Monotone;
-use Date::Parse qw(str2time);
-use Date::Format qw(time2str);
-
-package IkiWiki;
-
-my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate sha1sums
-
-sub check_config() { #{{{
- if (!defined($config{mtnrootdir})) {
- $config{mtnrootdir} = $config{srcdir};
- }
- if (! -d "$config{mtnrootdir}/_MTN") {
- error("Ikiwiki srcdir does not seem to be a Monotone workspace (or set the mtnrootdir)!");
- }
-
- chdir $config{srcdir}
- or error("Cannot chdir to $config{srcdir}: $!");
-
- my $child = open(MTN, "-|");
- if (! $child) {
- open STDERR, ">/dev/null";
- exec("mtn", "version") || error("mtn version failed to run");
- }
-
- my $version=undef;
- while (<MTN>) {
- if (/^monotone (\d+\.\d+) /) {
- $version=$1;
- }
- }
-
- close MTN || debug("mtn version exited $?");
-
- if (!defined($version)) {
- error("Cannot determine monotone version");
- }
- if ($version < 0.38) {
- error("Monotone version too old, is $version but required 0.38");
- }
-} #}}}
-
-sub get_rev () { #{{{
- my $sha1 = `mtn --root=$config{mtnrootdir} automate get_base_revision_id`;
-
- ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now
- if (! $sha1) {
- debug("Unable to get base revision for '$config{srcdir}'.")
- }
-
- return $sha1;
-} #}}}
-
-sub get_rev_auto ($) { #{{{
- my $automator=shift;
-
- my @results = $automator->call("get_base_revision_id");
-
- my $sha1 = $results[0];
- ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now
- if (! $sha1) {
- debug("Unable to get base revision for '$config{srcdir}'.")
- }
-
- return $sha1;
-} #}}}
-
-sub mtn_merge ($$$$) { #{{{
- my $leftRev=shift;
- my $rightRev=shift;
- my $branch=shift;
- my $author=shift;
-
- my $mergeRev;
-
- my $child = open(MTNMERGE, "-|");
- if (! $child) {
- open STDERR, ">&STDOUT";
- exec("mtn", "--root=$config{mtnrootdir}",
- "explicit_merge", $leftRev, $rightRev,
- $branch, "--author", $author, "--key",
- $config{mtnkey}) || error("mtn merge failed to run");
- }
-
- while (<MTNMERGE>) {
- if (/^mtn.\s.merged.\s($sha1_pattern)$/) {
- $mergeRev=$1;
- }
- }
-
- close MTNMERGE || return undef;
-
- debug("merged $leftRev, $rightRev to make $mergeRev");
-
- return $mergeRev;
-} #}}}
-
-sub commit_file_to_new_rev($$$$$$$$) { #{{{
- my $automator=shift;
- my $wsfilename=shift;
- my $oldFileID=shift;
- my $newFileContents=shift;
- my $oldrev=shift;
- my $branch=shift;
- my $author=shift;
- my $message=shift;
-
- #store the file
- my ($out, $err) = $automator->call("put_file", $oldFileID, $newFileContents);
- my ($newFileID) = ($out =~ m/^($sha1_pattern)$/);
- error("Failed to store file data for $wsfilename in repository")
- if (! defined $newFileID || length $newFileID != 40);
-
- # get the mtn filename rather than the workspace filename
- ($out, $err) = $automator->call("get_corresponding_path", $oldrev, $wsfilename, $oldrev);
- my ($filename) = ($out =~ m/^file "(.*)"$/);
- error("Couldn't find monotone repository path for file $wsfilename") if (! $filename);
- debug("Converted ws filename of $wsfilename to repos filename of $filename");
-
- # then stick in a new revision for this file
- my $manifest = "format_version \"1\"\n\n".
- "new_manifest [0000000000000000000000000000000000000000]\n\n".
- "old_revision [$oldrev]\n\n".
- "patch \"$filename\"\n".
- " from [$oldFileID]\n".
- " to [$newFileID]\n";
- ($out, $err) = $automator->call("put_revision", $manifest);
- my ($newRevID) = ($out =~ m/^($sha1_pattern)$/);
- error("Unable to make new monotone repository revision")
- if (! defined $newRevID || length $newRevID != 40);
- debug("put revision: $newRevID");
-
- # now we need to add certs for this revision...
- # author, branch, changelog, date
- $automator->call("cert", $newRevID, "author", $author);
- $automator->call("cert", $newRevID, "branch", $branch);
- $automator->call("cert", $newRevID, "changelog", $message);
- $automator->call("cert", $newRevID, "date",
- time2str("%Y-%m-%dT%T", time, "UTC"));
-
- debug("Added certs for rev: $newRevID");
- return $newRevID;
-} #}}}
-
-sub read_certs ($$) { #{{{
- my $automator=shift;
- my $rev=shift;
- my @results = $automator->call("certs", $rev);
- my @ret;
-
- my $line = $results[0];
- while ($line =~ m/\s+key\s"(.*?)"\nsignature\s"(ok|bad|unknown)"\n\s+name\s"(.*?)"\n\s+value\s"(.*?)"\n\s+trust\s"(trusted|untrusted)"\n/sg) {
- push @ret, {
- key => $1,
- signature => $2,
- name => $3,
- value => $4,
- trust => $5,
- };
- }
-
- return @ret;
-} #}}}
-
-sub get_changed_files ($$) { #{{{
- my $automator=shift;
- my $rev=shift;
-
- my @results = $automator->call("get_revision", $rev);
- my $changes=$results[0];
-
- my @ret;
- my %seen = ();
-
- while ($changes =~ m/\s*(add_file|patch|delete|rename)\s"(.*?)(?<!\\)"\n/sg) {
- my $file = $2;
- # don't add the same file multiple times
- if (! $seen{$file}) {
- push @ret, $file;
- $seen{$file} = 1;
- }
- }
-
- return @ret;
-} #}}}
-
-sub rcs_update () { #{{{
- check_config();
-
- if (defined($config{mtnsync}) && $config{mtnsync}) {
- if (system("mtn", "--root=$config{mtnrootdir}", "sync",
- "--quiet", "--ticker=none",
- "--key", $config{mtnkey}) != 0) {
- debug("monotone sync failed before update");
- }
- }
-
- if (system("mtn", "--root=$config{mtnrootdir}", "update", "--quiet") != 0) {
- debug("monotone update failed");
- }
-} #}}}
-
-sub rcs_prepedit ($) { #{{{
- my $file=shift;
-
- check_config();
-
- # For monotone, return the revision of the file when
- # editing begins.
- return get_rev();
-} #}}}
-
-sub rcs_commit ($$$;$$) { #{{{
- # Tries to commit the page; returns undef on _success_ and
- # a version of the page with the rcs's conflict markers on failure.
- # The file is relative to the srcdir.
- my $file=shift;
- my $message=shift;
- my $rcstoken=shift;
- my $user=shift;
- my $ipaddr=shift;
- my $author;
-
- if (defined $user) {
- $author="Web user: " . $user;
- }
- elsif (defined $ipaddr) {
- $author="Web IP: " . $ipaddr;
- }
- else {
- $author="Web: Anonymous";
- }
-
- check_config();
-
- my ($oldrev)= $rcstoken=~ m/^($sha1_pattern)$/; # untaint
- my $rev = get_rev();
- if (defined $rev && defined $oldrev && $rev ne $oldrev) {
- my $automator = Monotone->new();
- $automator->open_args("--root", $config{mtnrootdir}, "--key", $config{mtnkey});
-
- # Something has been committed, has this file changed?
- my ($out, $err);
- $automator->setOpts("r", $oldrev, "r", $rev);
- ($out, $err) = $automator->call("content_diff", $file);
- debug("Problem committing $file") if ($err ne "");
- my $diff = $out;
-
- if ($diff) {
- # Commit a revision with just this file changed off
- # the old revision.
- #
- # first get the contents
- debug("File changed: forming branch");
- my $newfile=readfile("$config{srcdir}/$file");
-
- # then get the old content ID from the diff
- if ($diff !~ m/^---\s$file\s+($sha1_pattern)$/m) {
- error("Unable to find previous file ID for $file");
- }
- my $oldFileID = $1;
-
- # get the branch we're working in
- ($out, $err) = $automator->call("get_option", "branch");
- chomp $out;
- error("Illegal branch name in monotone workspace") if ($out !~ m/^([-\@\w\.]+)$/);
- my $branch = $1;
-
- # then put the new content into the DB (and record the new content ID)
- my $newRevID = commit_file_to_new_rev($automator, $file, $oldFileID, $newfile, $oldrev, $branch, $author, $message);
-
- $automator->close();
-
- # if we made it to here then the file has been committed... revert the local copy
- if (system("mtn", "--root=$config{mtnrootdir}", "revert", $file) != 0) {
- debug("Unable to revert $file after merge on conflicted commit!");
- }
- debug("Divergence created! Attempting auto-merge.");
-
- # see if it will merge cleanly
- $ENV{MTN_MERGE}="fail";
- my $mergeResult = mtn_merge($newRevID, $rev, $branch, $author);
- $ENV{MTN_MERGE}="";
-
- # push any changes so far
- if (defined($config{mtnsync}) && $config{mtnsync}) {
- if (system("mtn", "--root=$config{mtnrootdir}", "push", "--quiet", "--ticker=none", "--key", $config{mtnkey}) != 0) {
- debug("monotone push failed");
- }
- }
-
- if (defined($mergeResult)) {
- # everything is merged - bring outselves up to date
- if (system("mtn", "--root=$config{mtnrootdir}",
- "update", "-r", $mergeResult) != 0) {
- debug("Unable to update to rev $mergeResult after merge on conflicted commit!");
- }
- }
- else {
- debug("Auto-merge failed. Using diff-merge to add conflict markers.");
-
- $ENV{MTN_MERGE}="diffutils";
- $ENV{MTN_MERGE_DIFFUTILS}="partial=true";
- $mergeResult = mtn_merge($newRevID, $rev, $branch, $author);
- $ENV{MTN_MERGE}="";
- $ENV{MTN_MERGE_DIFFUTILS}="";
-
- if (!defined($mergeResult)) {
- debug("Unable to insert conflict markers!");
- error("Your commit succeeded. Unfortunately, someone else committed something to the same ".
- "part of the wiki at the same time. Both versions are stored in the monotone repository, ".
- "but at present the different versions cannot be reconciled through the web interface. ".
- "Please use the non-web interface to resolve the conflicts.");
- }
-
- if (system("mtn", "--root=$config{mtnrootdir}",
- "update", "-r", $mergeResult) != 0) {
- debug("Unable to update to rev $mergeResult after conflict-enhanced merge on conflicted commit!");
- }
-
- # return "conflict enhanced" file to the user
- # for cleanup note, this relies on the fact
- # that ikiwiki seems to call rcs_prepedit()
- # again after we return
- return readfile("$config{srcdir}/$file");
- }
- return undef;
- }
- $automator->close();
- }
-
- # If we reached here then the file we're looking at hasn't changed
- # since $oldrev. Commit it.
-
- if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
- "--author", $author, "--key", $config{mtnkey}, "-m",
- possibly_foolish_untaint($message), $file) != 0) {
- debug("Traditional commit failed! Returning data as conflict.");
- my $conflict=readfile("$config{srcdir}/$file");
- if (system("mtn", "--root=$config{mtnrootdir}", "revert",
- "--quiet", $file) != 0) {
- debug("monotone revert failed");
- }
- return $conflict;
- }
- if (defined($config{mtnsync}) && $config{mtnsync}) {
- if (system("mtn", "--root=$config{mtnrootdir}", "push",
- "--quiet", "--ticker=none", "--key",
- $config{mtnkey}) != 0) {
- debug("monotone push failed");
- }
- }
-
- return undef # success
-} #}}}
-
-sub rcs_add ($) { #{{{
- my $file=shift;
-
- check_config();
-
- if (system("mtn", "--root=$config{mtnrootdir}", "add", "--quiet",
- $file) != 0) {
- error("Monotone add failed");
- }
-} #}}}
-
-sub rcs_recentchanges ($) { #{{{
- my $num=shift;
- my @ret;
-
- check_config();
-
- # use log --brief to get a list of revs, as this
- # gives the results in a nice order
- # (otherwise we'd have to do our own date sorting)
-
- my @revs;
-
- my $child = open(MTNLOG, "-|");
- if (! $child) {
- exec("mtn", "log", "--root=$config{mtnrootdir}", "--no-graph",
- "--brief") || error("mtn log failed to run");
- }
-
- while (($num >= 0) and (my $line = <MTNLOG>)) {
- if ($line =~ m/^($sha1_pattern)/) {
- push @revs, $1;
- $num -= 1;
- }
- }
- close MTNLOG || debug("mtn log exited $?");
-
- my $automator = Monotone->new();
- $automator->open(undef, $config{mtnrootdir});
-
- while (@revs != 0) {
- my $rev = shift @revs;
- # first go through and figure out the messages, etc
-
- my $certs = [read_certs($automator, $rev)];
-
- my $user;
- my $when;
- my $committype;
- my (@pages, @message);
-
- foreach my $cert (@$certs) {
- if ($cert->{signature} eq "ok" &&
- $cert->{trust} eq "trusted") {
- if ($cert->{name} eq "author") {
- $user = $cert->{value};
- # detect the source of the commit
- # from the changelog
- if ($cert->{key} eq $config{mtnkey}) {
- $committype = "web";
- } else {
- $committype = "monotone";
- }
- } elsif ($cert->{name} eq "date") {
- $when = str2time($cert->{value}, 'UTC');
- } elsif ($cert->{name} eq "changelog") {
- my $messageText = $cert->{value};
- # split the changelog into multiple
- # lines
- foreach my $msgline (split(/\n/, $messageText)) {
- push @message, { line => $msgline };
- }
- }
- }
- }
-
- my @changed_files = get_changed_files($automator, $rev);
- my $file;
-
- my ($out, $err) = $automator->call("parents", $rev);
- my @parents = ($out =~ m/^($sha1_pattern)$/);
- my $parent = $parents[0];
-
- foreach $file (@changed_files) {
- next unless length $file;
-
- if (defined $config{diffurl} and (@parents == 1)) {
- my $diffurl=$config{diffurl};
- $diffurl=~s/\[\[r1\]\]/$parent/g;
- $diffurl=~s/\[\[r2\]\]/$rev/g;
- $diffurl=~s/\[\[file\]\]/$file/g;
- push @pages, {
- page => pagename($file),
- diffurl => $diffurl,
- };
- }
- else {
- push @pages, {
- page => pagename($file),
- }
- }
- }
-
- push @ret, {
- rev => $rev,
- user => $user,
- committype => $committype,
- when => $when,
- message => [@message],
- pages => [@pages],
- } if @pages;
- }
-
- $automator->close();
-
- return @ret;
-} #}}}
-
-sub rcs_diff ($) { #{{{
- # TODO
-} #}}}
-
-sub rcs_getctime ($) { #{{{
- my $file=shift;
-
- check_config();
-
- my $child = open(MTNLOG, "-|");
- if (! $child) {
- exec("mtn", "log", "--root=$config{mtnrootdir}", "--no-graph",
- "--brief", $file) || error("mtn log $file failed to run");
- }
-
- my $firstRev;
- while (<MTNLOG>) {
- if (/^($sha1_pattern)/) {
- $firstRev=$1;
- }
- }
- close MTNLOG || debug("mtn log $file exited $?");
-
- if (! defined $firstRev) {
- debug "failed to parse mtn log for $file";
- return 0;
- }
-
- my $automator = Monotone->new();
- $automator->open(undef, $config{mtnrootdir});
-
- my $certs = [read_certs($automator, $firstRev)];
-
- $automator->close();
-
- my $date;
-
- foreach my $cert (@$certs) {
- if ($cert->{signature} eq "ok" && $cert->{trust} eq "trusted") {
- if ($cert->{name} eq "date") {
- $date = $cert->{value};
- }
- }
- }
-
- if (! defined $date) {
- debug "failed to find date cert for revision $firstRev when looking for creation time of $file";
- return 0;
- }
-
- $date=str2time($date, 'UTC');
- debug("found ctime ".localtime($date)." for $file");
- return $date;
-} #}}}
-
-1
+++ /dev/null
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use IkiWiki;
-use POSIX qw(setlocale LC_CTYPE);
-
-package IkiWiki::Rcs::svn;
-
-sub import { #{{{
- if (exists $IkiWiki::config{svnpath}) {
- # code depends on the path not having extraneous slashes
- $IkiWiki::config{svnpath}=~tr#/#/#s;
- $IkiWiki::config{svnpath}=~s/\/$//;
- $IkiWiki::config{svnpath}=~s/^\///;
- }
-} #}}}
-
-
-package IkiWiki;
-
-# svn needs LC_CTYPE set to a UTF-8 locale, so try to find one. Any will do.
-sub find_lc_ctype() {
- my $current = setlocale(LC_CTYPE());
- return $current if $current =~ m/UTF-?8$/i;
-
- # Make some obvious attempts to avoid calling `locale -a`
- foreach my $locale ("$current.UTF-8", "en_US.UTF-8", "en_GB.UTF-8") {
- return $locale if setlocale(LC_CTYPE(), $locale);
- }
-
- # Try to get all available locales and pick the first UTF-8 one found.
- if (my @locale = grep(/UTF-?8$/i, `locale -a`)) {
- chomp @locale;
- return $locale[0] if setlocale(LC_CTYPE(), $locale[0]);
- }
-
- # fallback to the current locale
- return $current;
-} # }}}
-$ENV{LC_CTYPE} = $ENV{LC_CTYPE} || find_lc_ctype();
-
-sub svn_info ($$) { #{{{
- my $field=shift;
- my $file=shift;
-
- my $info=`LANG=C svn info $file`;
- my ($ret)=$info=~/^$field: (.*)$/m;
- return $ret;
-} #}}}
-
-sub rcs_update () { #{{{
- if (-d "$config{srcdir}/.svn") {
- if (system("svn", "update", "--quiet", $config{srcdir}) != 0) {
- warn("svn update failed\n");
- }
- }
-} #}}}
-
-sub rcs_prepedit ($) { #{{{
- # Prepares to edit a file under revision control. Returns a token
- # that must be passed into rcs_commit when the file is ready
- # for committing.
- # The file is relative to the srcdir.
- my $file=shift;
-
- if (-d "$config{srcdir}/.svn") {
- # For subversion, return the revision of the file when
- # editing begins.
- my $rev=svn_info("Revision", "$config{srcdir}/$file");
- return defined $rev ? $rev : "";
- }
-} #}}}
-
-sub rcs_commit ($$$;$$) { #{{{
- # Tries to commit the page; returns undef on _success_ and
- # a version of the page with the rcs's conflict markers on failure.
- # The file is relative to the srcdir.
- my $file=shift;
- my $message=shift;
- my $rcstoken=shift;
- my $user=shift;
- my $ipaddr=shift;
-
- if (defined $user) {
- $message="web commit by $user".(length $message ? ": $message" : "");
- }
- elsif (defined $ipaddr) {
- $message="web commit from $ipaddr".(length $message ? ": $message" : "");
- }
-
- if (-d "$config{srcdir}/.svn") {
- # Check to see if the page has been changed by someone
- # else since rcs_prepedit was called.
- my ($oldrev)=$rcstoken=~/^([0-9]+)$/; # untaint
- my $rev=svn_info("Revision", "$config{srcdir}/$file");
- if (defined $rev && defined $oldrev && $rev != $oldrev) {
- # Merge their changes into the file that we've
- # changed.
- if (system("svn", "merge", "--quiet", "-r$oldrev:$rev",
- "$config{srcdir}/$file", "$config{srcdir}/$file") != 0) {
- warn("svn merge -r$oldrev:$rev failed\n");
- }
- }
-
- if (system("svn", "commit", "--quiet",
- "--encoding", "UTF-8", "-m",
- possibly_foolish_untaint($message),
- $config{srcdir}) != 0) {
- my $conflict=readfile("$config{srcdir}/$file");
- if (system("svn", "revert", "--quiet", "$config{srcdir}/$file") != 0) {
- warn("svn revert failed\n");
- }
- return $conflict;
- }
- }
- return undef # success
-} #}}}
-
-sub rcs_add ($) { #{{{
- # filename is relative to the root of the srcdir
- my $file=shift;
-
- if (-d "$config{srcdir}/.svn") {
- my $parent=dirname($file);
- while (! -d "$config{srcdir}/$parent/.svn") {
- $file=$parent;
- $parent=dirname($file);
- }
-
- if (system("svn", "add", "--quiet", "$config{srcdir}/$file") != 0) {
- warn("svn add failed\n");
- }
- }
-} #}}}
-
-sub rcs_recentchanges ($) { #{{{
- my $num=shift;
- my @ret;
-
- return unless -d "$config{srcdir}/.svn";
-
- eval q{
- use Date::Parse;
- use XML::SAX;
- use XML::Simple;
- };
- error($@) if $@;
-
- # avoid using XML::SAX::PurePerl, it's buggy with UTF-8 data
- my @parsers = map { ${$_}{Name} } @{XML::SAX->parsers()};
- do {
- $XML::Simple::PREFERRED_PARSER = pop @parsers;
- } until $XML::Simple::PREFERRED_PARSER ne 'XML::SAX::PurePerl';
-
- # --limit is only supported on Subversion 1.2.0+
- my $svn_version=`svn --version -q`;
- my $svn_limit='';
- $svn_limit="--limit $num"
- if $svn_version =~ /\d\.(\d)\.\d/ && $1 >= 2;
-
- my $svn_url=svn_info("URL", $config{srcdir});
- my $xml = XMLin(scalar `svn $svn_limit --xml -v log '$svn_url'`,
- ForceArray => [ 'logentry', 'path' ],
- GroupTags => { paths => 'path' },
- KeyAttr => { path => 'content' },
- );
- foreach my $logentry (@{$xml->{logentry}}) {
- my (@pages, @message);
-
- my $rev = $logentry->{revision};
- my $user = $logentry->{author};
-
- my $when=str2time($logentry->{date}, 'UTC');
-
- foreach my $msgline (split(/\n/, $logentry->{msg})) {
- push @message, { line => $msgline };
- }
-
- my $committype="web";
- if (defined $message[0] &&
- $message[0]->{line}=~/$config{web_commit_regexp}/) {
- $user=defined $2 ? "$2" : "$3";
- $message[0]->{line}=$4;
- }
- else {
- $committype="svn";
- }
-
- foreach my $file (keys %{$logentry->{paths}}) {
- if (length $config{svnpath}) {
- next unless $file=~/^\/\Q$config{svnpath}\E\/([^ ]+)(?:$|\s)/;
- $file=$1;
- }
-
- my $diffurl=$config{diffurl};
- $diffurl=~s/\[\[file\]\]/$file/g;
- $diffurl=~s/\[\[r1\]\]/$rev - 1/eg;
- $diffurl=~s/\[\[r2\]\]/$rev/g;
-
- push @pages, {
- page => pagename($file),
- diffurl => $diffurl,
- } if length $file;
- }
- push @ret, {
- rev => $rev,
- user => $user,
- committype => $committype,
- when => $when,
- message => [@message],
- pages => [@pages],
- } if @pages;
- return @ret if @ret >= $num;
- }
-
- return @ret;
-} #}}}
-
-sub rcs_diff ($) { #{{{
- my $rev=possibly_foolish_untaint(int(shift));
- return `svnlook diff $config{svnrepo} -r$rev --no-diff-deleted`;
-} #}}}
-
-sub rcs_getctime ($) { #{{{
- my $file=shift;
-
- my $svn_log_infoline=qr/^r\d+\s+\|\s+[^\s]+\s+\|\s+(\d+-\d+-\d+\s+\d+:\d+:\d+\s+[-+]?\d+).*/;
-
- my $child = open(SVNLOG, "-|");
- if (! $child) {
- exec("svn", "log", $file) || error("svn log $file failed to run");
- }
-
- my $date;
- while (<SVNLOG>) {
- if (/$svn_log_infoline/) {
- $date=$1;
- }
- }
- close SVNLOG || warn "svn log $file exited $?";
-
- if (! defined $date) {
- warn "failed to parse svn log for $file\n";
- return 0;
- }
-
- eval q{use Date::Parse};
- error($@) if $@;
- $date=str2time($date);
- debug("found ctime ".localtime($date)." for $file");
- return $date;
-} #}}}
-
-1
+++ /dev/null
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use IkiWiki;
-
-package IkiWiki;
-
-sub quiet_system (@) {
- # See Debian bug #385939.
- open (SAVEOUT, ">&STDOUT");
- close STDOUT;
- open (STDOUT, ">/dev/null");
- my $ret=system(@_);
- close STDOUT;
- open (STDOUT, ">&SAVEOUT");
- close SAVEOUT;
- return $ret;
-}
-
-sub rcs_update () { #{{{
- if (-d "$config{srcdir}/{arch}") {
- if (quiet_system("tla", "replay", "-d", $config{srcdir}) != 0) {
- warn("tla replay failed\n");
- }
- }
-} #}}}
-
-sub rcs_prepedit ($) { #{{{
- my $file=shift;
-
- if (-d "$config{srcdir}/{arch}") {
- # For Arch, return the tree-id of archive when
- # editing begins.
- my $rev=`tla tree-id $config{srcdir}`;
- return defined $rev ? $rev : "";
- }
-} #}}}
-
-sub rcs_commit ($$$;$$) { #{{{
- my $file=shift;
- my $message=shift;
- my $rcstoken=shift;
- my $user=shift;
- my $ipaddr=shift;
-
- if (defined $user) {
- $message="web commit by $user".(length $message ? ": $message" : "");
- }
- elsif (defined $ipaddr) {
- $message="web commit from $ipaddr".(length $message ? ": $message" : "");
- }
-
- if (-d "$config{srcdir}/{arch}") {
- # Check to see if the page has been changed by someone
- # else since rcs_prepedit was called.
- my ($oldrev)=$rcstoken=~/^([A-Za-z0-9@\/._-]+)$/; # untaint
- my $rev=`tla tree-id $config{srcdir}`;
- if (defined $rev && defined $oldrev && $rev ne $oldrev) {
- # Merge their changes into the file that we've
- # changed.
- if (quiet_system("tla", "update", "-d",
- "$config{srcdir}") != 0) {
- warn("tla update failed\n");
- }
- }
-
- if (quiet_system("tla", "commit",
- "-L".possibly_foolish_untaint($message),
- '-d', $config{srcdir}) != 0) {
- my $conflict=readfile("$config{srcdir}/$file");
- if (system("tla", "undo", "-n", "--quiet", "-d", "$config{srcdir}") != 0) {
- warn("tla undo failed\n");
- }
- return $conflict;
- }
- }
- return undef # success
-} #}}}
-
-sub rcs_add ($) { #{{{
- my $file=shift;
-
- if (-d "$config{srcdir}/{arch}") {
- if (quiet_system("tla", "add", "$config{srcdir}/$file") != 0) {
- warn("tla add failed\n");
- }
- }
-} #}}}
-
-sub rcs_recentchanges ($) {
- my $num=shift;
- my @ret;
-
- return unless -d "$config{srcdir}/{arch}";
-
- eval q{use Date::Parse};
- error($@) if $@;
- eval q{use Mail::Header};
- error($@) if $@;
-
- my $logs = `tla logs -d $config{srcdir}`;
- my @changesets = reverse split(/\n/, $logs);
-
- for (my $i=0; $i<$num && $i<$#changesets; $i++) {
- my ($change)=$changesets[$i]=~/^([A-Za-z0-9@\/._-]+)$/; # untaint
-
- open(LOG, "tla cat-log -d $config{srcdir} $change|");
- my $head = Mail::Header->new(\*LOG);
- close(LOG);
-
- my $rev = $head->get("Revision");
- my $summ = $head->get("Summary");
- my $newfiles = $head->get("New-files");
- my $modfiles = $head->get("Modified-files");
- my $remfiles = $head->get("Removed-files");
- my $user = $head->get("Creator");
-
- my @paths = grep { !/^(.*\/)?\.arch-ids\/.*\.id$/ }
- split(/ /, "$newfiles $modfiles .arch-ids/fake.id");
-
- my $sdate = $head->get("Standard-date");
- my $when = str2time($sdate, 'UTC');
-
- my $committype = "web";
- if (defined $summ && $summ =~ /$config{web_commit_regexp}/) {
- $user = defined $2 ? "$2" : "$3";
- $summ = $4;
- }
- else {
- $committype="tla";
- }
-
- my @message;
- push @message, { line => $summ };
-
- my @pages;
-
- foreach my $file (@paths) {
- my $diffurl=$config{diffurl};
- $diffurl=~s/\[\[file\]\]/$file/g;
- $diffurl=~s/\[\[rev\]\]/$change/g;
- push @pages, {
- page => pagename($file),
- diffurl => $diffurl,
- } if length $file;
- }
- push @ret, {
- rev => $change,
- user => $user,
- committype => $committype,
- when => $when,
- message => [@message],
- pages => [@pages],
- } if @pages;
-
- last if $i == $num;
- }
-
- return @ret;
-}
-
-sub rcs_diff ($) { #{{{
- my $rev=shift;
- my $logs = `tla logs -d $config{srcdir}`;
- my @changesets = reverse split(/\n/, $logs);
- my $i;
-
- for($i=0;$i<$#changesets;$i++) {
- last if $changesets[$i] eq $rev;
- }
-
- my $revminusone = $changesets[$i+1];
- return `tla diff -d $config{srcdir} $revminusone`;
-} #}}}
-
-sub rcs_getctime ($) { #{{{
- my $file=shift;
- eval q{use Date::Parse};
- error($@) if $@;
- eval q{use Mail::Header};
- error($@) if $@;
-
- my $logs = `tla logs -d $config{srcdir}`;
- my @changesets = reverse split(/\n/, $logs);
- my $sdate;
-
- for (my $i=0; $i<$#changesets; $i++) {
- my $change = $changesets[$i];
-
- open(LOG, "tla cat-log -d $config{srcdir} $change|");
- my $head = Mail::Header->new(\*LOG);
- close(LOG);
-
- $sdate = $head->get("Standard-date");
- my $newfiles = $head->get("New-files");
-
- my ($lastcreation) = grep {/^$file$/} split(/ /, "$newfiles");
- last if defined($lastcreation);
- }
-
- my $date=str2time($sdate, 'UTC');
- debug("found ctime ".localtime($date)." for $file");
- return $date;
-} #}}}
-
-1
--- /dev/null
+#!/usr/bin/perl
+
+package IkiWiki::Receive;
+
+use warnings;
+use strict;
+use IkiWiki;
+
+sub getuser () {
+ my $user=(getpwuid(exists $ENV{CALLER_UID} ? $ENV{CALLER_UID} : $<))[0];
+ if (! defined $user) {
+ error("cannot determine username for $<");
+ }
+ return $user;
+}
+
+sub trusted () {
+ my $user=getuser();
+ return ! ref $config{untrusted_committers} ||
+ ! grep { $_ eq $user } @{$config{untrusted_committers}};
+}
+
+sub gen_wrapper () {
+ # Test for commits from untrusted committers in the wrapper, to
+ # avoid loading ikiwiki at all for trusted commits.
+
+ my $ret=<<"EOF";
+ {
+ int u=getuid();
+EOF
+ $ret.="\t\tif ( ".
+ join("&&", map {
+ my $uid=getpwnam($_);
+ if (! defined $uid) {
+ error(sprintf(gettext("cannot determine id of untrusted committer %s"), $_));
+ }
+ "u != $uid";
+ } @{$config{untrusted_committers}}).
+ ") exit(0);\n";
+ $ret.=<<"EOF";
+ asprintf(&s, "CALLER_UID=%i", u);
+ newenviron[i++]=s;
+ }
+EOF
+ return $ret;
+}
+
+sub test () {
+ exit 0 if trusted();
+
+ IkiWiki::lockwiki();
+ IkiWiki::loadindex();
+
+ # Dummy up a cgi environment to use when calling check_canedit
+ # and friends.
+ eval q{use CGI};
+ error($@) if $@;
+ my $cgi=CGI->new;
+ $ENV{REMOTE_ADDR}='unknown' unless exists $ENV{REMOTE_ADDR};
+
+ # And dummy up a session object.
+ require IkiWiki::CGI;
+ my $session=IkiWiki::cgi_getsession($cgi);
+ $session->param("name", getuser());
+ # Make sure whatever user was authed is in the
+ # userinfo db.
+ require IkiWiki::UserInfo;
+ if (! IkiWiki::userinfo_get($session->param("name"), "regdate")) {
+ IkiWiki::userinfo_setall($session->param("name"), {
+ email => "",
+ password => "",
+ regdate => time,
+ }) || error("failed adding user");
+ }
+
+ my %newfiles;
+
+ foreach my $change (IkiWiki::rcs_receive()) {
+ # This untaint is safe because we check file_pruned and
+ # wiki_file_regexp.
+ my ($file)=$change->{file}=~/$config{wiki_file_regexp}/;
+ $file=IkiWiki::possibly_foolish_untaint($file);
+ if (! defined $file || ! length $file ||
+ IkiWiki::file_pruned($file, $config{srcdir})) {
+ error(gettext("bad file name %s"), $file);
+ }
+
+ my $type=pagetype($file);
+ my $page=pagename($file) if defined $type;
+
+ if ($change->{action} eq 'add') {
+ $newfiles{$file}=1;
+ }
+
+ if ($change->{action} eq 'change' ||
+ $change->{action} eq 'add') {
+ if (defined $page) {
+ if (IkiWiki->can("check_canedit")) {
+ IkiWiki::check_canedit($page, $cgi, $session);
+ next;
+ }
+ }
+ else {
+ if (IkiWiki::Plugin::attachment->can("check_canattach")) {
+ IkiWiki::Plugin::attachment::check_canattach($session, $file, $change->{path});
+ next;
+ }
+ }
+ }
+ elsif ($change->{action} eq 'remove') {
+ # check_canremove tests to see if the file is present
+ # on disk. This will fail is a single commit adds a
+ # file and then removes it again. Avoid the problem
+ # by not testing the removal in such pairs of changes.
+ # (The add is still tested, just to make sure that
+ # no data is added to the repo that a web edit
+ # could add.)
+ next if $newfiles{$file};
+
+ if (IkiWiki::Plugin::remove->can("check_canremove")) {
+ IkiWiki::Plugin::remove::check_canremove(defined $page ? $page : $file, $cgi, $session);
+ next;
+ }
+ }
+ else {
+ error "unknown action ".$change->{action};
+ }
+
+ error sprintf(gettext("you are not allowed to change %s"), $file);
+ }
+
+ exit 0;
+}
+
+1
use Encode;
my %backlinks;
-my $backlinks_calculated=0;
+our %brokenlinks;
+my $links_calculated=0;
-sub calculate_backlinks () { #{{{
- return if $backlinks_calculated;
- %backlinks=();
+sub calculate_links () {
+ return if $links_calculated;
+ %backlinks=%brokenlinks=();
foreach my $page (keys %links) {
foreach my $link (@{$links{$page}}) {
my $bestlink=bestlink($page, $link);
- if (length $bestlink && $bestlink ne $page) {
- $backlinks{$bestlink}{$page}=1;
+ if (length $bestlink) {
+ $backlinks{$bestlink}{$page}=1
+ if $bestlink ne $page;
+ }
+ else {
+ push @{$brokenlinks{$link}}, $page;
}
}
}
- $backlinks_calculated=1;
-} #}}}
+ $links_calculated=1;
+}
-sub backlinks ($) { #{{{
+sub backlink_pages ($) {
my $page=shift;
- calculate_backlinks();
+ calculate_links();
+
+ return keys %{$backlinks{$page}};
+}
+
+sub backlinks ($) {
+ my $page=shift;
my @links;
- foreach my $p (keys %{$backlinks{$page}}) {
+ foreach my $p (backlink_pages($page)) {
my $href=urlto($p, $page);
# Trim common dir prefixes from both pages.
push @links, { url => $href, page => pagetitle($p_trimmed) };
}
return @links;
-} #}}}
-
-sub parentlinks ($) { #{{{
- my $page=shift;
-
- my @ret;
- my $pagelink="";
- my $path="";
- my $title=$config{wikiname};
-
- foreach my $dir (split("/", $page)) {
- next if $dir eq 'index';
- push @ret, { url => urlto($path, $page), page => $title };
- $path.="/".$dir;
- $title=pagetitle($dir);
- }
- return @ret;
-} #}}}
+}
-sub genpage ($$) { #{{{
+sub genpage ($$) {
my $page=shift;
my $content=shift;
my $actions=0;
if (length $config{cgiurl}) {
- $template->param(editurl => cgiurl(do => "edit", page => $page));
- $template->param(prefsurl => cgiurl(do => "prefs"));
+ $template->param(editurl => cgiurl(do => "edit", page => $page))
+ if IkiWiki->can("cgi_editpage");
+ $template->param(prefsurl => cgiurl(do => "prefs"))
+ if exists $hooks{auth};
$actions++;
}
- if (length $config{historyurl}) {
+ if (defined $config{historyurl} && length $config{historyurl}) {
my $u=$config{historyurl};
$u=~s/\[\[file\]\]/$pagesources{$page}/g;
$template->param(historyurl => $u);
$actions++;
}
if ($config{discussion}) {
- my $discussionlink=gettext("discussion");
- if ($page !~ /.*\/\Q$discussionlink\E$/ &&
+ if ($page !~ /.*\/\Q$config{discussionpage}\E$/ &&
(length $config{cgiurl} ||
- exists $links{$page."/".$discussionlink})) {
- $template->param(discussionlink => htmllink($page, $page, gettext("Discussion"), noimageinline => 1, forcesubpage => 1));
+ exists $links{$page."/".$config{discussionpage}})) {
+ $template->param(discussionlink => htmllink($page, $page, $config{discussionpage}, noimageinline => 1, forcesubpage => 1));
$actions++;
}
}
? $config{wikiname}
: pagetitle(basename($page)),
wikiname => $config{wikiname},
- parentlinks => [parentlinks($page)],
content => $content,
backlinks => $backlinks,
more_backlinks => $more_backlinks,
});
$content=$template->output;
+
+ run_hooks(postscan => sub {
+ shift->(page => $page, content => $content);
+ });
run_hooks(format => sub {
$content=shift->(
});
return $content;
-} #}}}
+}
-sub scan ($) { #{{{
+sub scan ($) {
my $file=shift;
my $type=pagetype($file);
if ($config{discussion}) {
# Discussion links are a special case since they're
# not in the text of the page, but on its template.
- $links{$page}=[ $page."/".gettext("discussion") ];
+ $links{$page}=[ $page."/".lc($config{discussionpage}) ];
}
else {
$links{$page}=[];
else {
will_render($file, $file, 1);
}
-} #}}}
+}
-sub fast_file_copy (@) { #{{{
+sub fast_file_copy (@) {
my $srcfile=shift;
my $destfile=shift;
my $srcfd=shift;
}
}
-sub render ($) { #{{{
+sub render ($) {
my $file=shift;
my $type=pagetype($file);
will_render($file, $file, 1);
if ($config{hardlink}) {
- prep_writefile($file, $config{destdir});
- unlink($config{destdir}."/".$file);
- if (link($srcfile, $config{destdir}."/".$file)) {
- return;
+ # only hardlink if owned by same user
+ my @stat=stat($srcfile);
+ if ($stat[4] == $>) {
+ prep_writefile($file, $config{destdir});
+ unlink($config{destdir}."/".$file);
+ if (link($srcfile, $config{destdir}."/".$file)) {
+ return;
+ }
}
# if hardlink fails, fall back to copying
}
fast_file_copy($srcfile, $file, $srcfd, @_);
});
}
-} #}}}
+}
-sub prune ($) { #{{{
+sub prune ($) {
my $file=shift;
unlink($file);
while (rmdir($dir)) {
$dir=dirname($dir);
}
-} #}}}
+}
-sub refresh () { #{{{
- # security check, avoid following symlinks in the srcdir path
+sub srcdir_check () {
+ # security check, avoid following symlinks in the srcdir path by default
my $test=$config{srcdir};
while (length $test) {
- if (-l $test) {
- error("symlink found in srcdir path ($test)");
+ if (-l $test && ! $config{allow_symlinks_before_srcdir}) {
+ error(sprintf(gettext("symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to allow this"), $test));
}
unless ($test=~s/\/+$//) {
$test=dirname($test);
}
}
- run_hooks(refresh => sub { shift->() });
+}
- # find existing pages
- my %exists;
- my @files;
+sub find_src_files () {
+ my (@files, %pages);
eval q{use File::Find};
error($@) if $@;
find({
else {
$f=~s/^\Q$config{srcdir}\E\/?//;
push @files, $f;
- $exists{pagename($f)}=1;
+ my $pagename = pagename($f);
+ if ($pages{$pagename}) {
+ debug(sprintf(gettext("%s has multiple possible source pages"), $pagename));
+ }
+ $pages{$pagename}=1;
}
}
},
if (! -l "$config{srcdir}/$f" &&
! -e _) {
my $page=pagename($f);
- if (! $exists{$page}) {
+ if (! $pages{$page}) {
push @files, $f;
- $exists{$page}=1;
+ $pages{$page}=1;
}
}
}
}, $dir);
};
+ # Returns a list of all source files found, and a hash of
+ # the corresponding page names.
+ return \@files, \%pages;
+}
+
+sub refresh () {
+ srcdir_check();
+ run_hooks(refresh => sub { shift->() });
+ my ($files, $exists)=find_src_files();
+
my (%rendered, @add, @del, @internal);
# check for added or removed pages
- foreach my $file (@files) {
+ foreach my $file (@$files) {
my $page=pagename($file);
+ if (exists $pagesources{$page} && $pagesources{$page} ne $file) {
+ # the page has changed its type
+ $forcerebuild{$page}=1;
+ }
$pagesources{$page}=$file;
if (! $pagemtime{$page}) {
if (isinternal($page)) {
}
}
foreach my $page (keys %pagemtime) {
- if (! $exists{$page}) {
+ if (! $exists->{$page}) {
if (isinternal($page)) {
push @internal, $pagesources{$page};
}
$links{$page}=[];
$renderedfiles{$page}=[];
$pagemtime{$page}=0;
- prune($config{destdir}."/".$_)
- foreach @{$oldrenderedfiles{$page}};
+ foreach my $old (@{$oldrenderedfiles{$page}}) {
+ prune($config{destdir}."/".$old);
+ }
delete $pagesources{$page};
- foreach (keys %destsources) {
- if ($destsources{$_} eq $page) {
- delete $destsources{$_};
+ foreach my $source (keys %destsources) {
+ if ($destsources{$source} eq $page) {
+ delete $destsources{$source};
}
}
}
# find changed and new files
my @needsbuild;
- foreach my $file (@files) {
+ foreach my $file (@$files) {
my $page=pagename($file);
my ($srcfile, @stat)=srcfile_stat($file);
if (! exists $pagemtime{$page} ||
debug(sprintf(gettext("scanning %s"), $file));
scan($file);
}
- calculate_backlinks();
+ calculate_links();
foreach my $file (@needsbuild) {
- debug(sprintf(gettext("rendering %s"), $file));
+ debug(sprintf(gettext("building %s"), $file));
render($file);
$rendered{$file}=1;
}
foreach my $page (keys %{$backlinks{$p}}) {
my $file=$pagesources{$page};
next if $rendered{$file};
- debug(sprintf(gettext("rendering %s, which links to %s"), $file, $p));
+ debug(sprintf(gettext("building %s, which links to %s"), $file, $p));
render($file);
$rendered{$file}=1;
}
my @changed=(keys %rendered, @del);
# rebuild dependant pages
- foreach my $f (@files) {
+ F: foreach my $f (@$files) {
next if $rendered{$f};
my $p=pagename($f);
if (exists $depends{$p}) {
- # only consider internal files
- # if the page explicitly depends on such files
- foreach my $file (@changed, $depends{$p}=~/internal\(/ ? @internal : ()) {
- next if $f eq $file;
- my $page=pagename($file);
- if (pagespec_match($page, $depends{$p}, location => $p)) {
- debug(sprintf(gettext("rendering %s, which depends on %s"), $f, $page));
- render($f);
- $rendered{$f}=1;
- last;
+ foreach my $d (keys %{$depends{$p}}) {
+ my $sub=pagespec_translate($d);
+ next if $@ || ! defined $sub;
+
+ # only consider internal files
+ # if the page explicitly depends
+ # on such files
+ foreach my $file (@changed, $d =~ /internal\(/ ? @internal : ()) {
+ next if $file eq $f;
+ my $page=pagename($file);
+ if ($sub->($page, location => $p)) {
+ debug(sprintf(gettext("building %s, which depends on %s"), $f, $page));
+ render($f);
+ $rendered{$f}=1;
+ next F;
+ }
}
}
}
my $linkfile=$pagesources{$link};
if (defined $linkfile) {
next if $rendered{$linkfile};
- debug(sprintf(gettext("rendering %s, to update its backlinks"), $linkfile));
+ debug(sprintf(gettext("building %s, to update its backlinks"), $linkfile));
render($linkfile);
$rendered{$linkfile}=1;
}
my $page=pagename($src);
foreach my $file (@{$oldrenderedfiles{$page}}) {
if (! grep { $_ eq $file } @{$renderedfiles{$page}}) {
- debug(sprintf(gettext("removing %s, no longer rendered by %s"), $file, $page));
+ debug(sprintf(gettext("removing %s, no longer built by %s"), $file, $page));
prune($config{destdir}."/".$file);
}
}
if (%rendered) {
run_hooks(change => sub { shift->(keys %rendered) });
}
-} #}}}
+}
-sub commandline_render () { #{{{
+sub commandline_render () {
lockwiki();
loadindex();
unlockwiki();
$file=~s/\Q$config{srcdir}\E\/?//;
my $type=pagetype($file);
- die sprintf(gettext("ikiwiki: cannot render %s"), $srcfile)."\n" unless defined $type;
+ die sprintf(gettext("ikiwiki: cannot build %s"), $srcfile)."\n" unless defined $type;
my $content=readfile($srcfile);
my $page=pagename($file);
$pagesources{$page}=$file;
$content=linkify($page, $page, $content);
$content=htmlize($page, $page, $type, $content);
$pagemtime{$page}=(stat($srcfile))[9];
+ $pagectime{$page}=$pagemtime{$page} if ! exists $pagectime{$page};
print genpage($page, $content);
exit 0;
-} #}}}
+}
1
#!/usr/bin/perl
+# Ikiwiki setup files are perl files that 'use IkiWiki::Setup::foo',
+# passing it some sort of configuration data.
+
+package IkiWiki::Setup;
use warnings;
use strict;
use IkiWiki;
use open qw{:utf8 :std};
+use File::Spec;
-package IkiWiki;
+sub load ($) {
+ my $setup=IkiWiki::possibly_foolish_untaint(shift);
+ $config{setupfile}=File::Spec->rel2abs($setup);
-sub setup () { # {{{
- my $setup=possibly_foolish_untaint($config{setup});
- delete $config{setup};
#translators: The first parameter is a filename, and the second
#translators: is a (probably not translated) error message.
open (IN, $setup) || error(sprintf(gettext("cannot read %s: %s"), $setup, $!));
eval $code;
error("$setup: ".$@) if $@;
+}
+
+sub merge ($) {
+ # Merge setup into existing config and untaint.
+ my %setup=%{shift()};
+
+ if (exists $setup{add_plugins} && exists $config{add_plugins}) {
+ push @{$setup{add_plugins}}, @{$config{add_plugins}};
+ }
+ if (exists $setup{exclude}) {
+ push @{$config{wiki_file_prune_regexps}}, $setup{exclude};
+ }
+ foreach my $c (keys %setup) {
+ if (defined $setup{$c}) {
+ if (! ref $setup{$c} || ref $setup{$c} eq 'Regexp') {
+ $config{$c}=IkiWiki::possibly_foolish_untaint($setup{$c});
+ }
+ elsif (ref $setup{$c} eq 'ARRAY') {
+ if ($c eq 'wrappers') {
+ # backwards compatability code
+ $config{$c}=$setup{$c};
+ }
+ else {
+ $config{$c}=[map { IkiWiki::possibly_foolish_untaint($_) } @{$setup{$c}}]
+ }
+ }
+ elsif (ref $setup{$c} eq 'HASH') {
+ foreach my $key (keys %{$setup{$c}}) {
+ $config{$c}{$key}=IkiWiki::possibly_foolish_untaint($setup{$c}{$key});
+ }
+ }
+ }
+ else {
+ $config{$c}=undef;
+ }
+ }
+
+ if (length $config{cgi_wrapper}) {
+ push @{$config{wrappers}}, {
+ cgi => 1,
+ wrapper => $config{cgi_wrapper},
+ wrappermode => (defined $config{cgi_wrappermode} ? $config{cgi_wrappermode} : "06755"),
+ };
+ }
+}
+
+sub getsetup () {
+ # Gets all available setup data from all plugins. Returns an
+ # ordered list of [plugin, setup] pairs.
+ my @ret;
+
+ # disable logging to syslog while dumping, broken plugins may
+ # whine when loaded
+ my $syslog=$config{syslog};
+ $config{syslog}=undef;
+
+ # Load all plugins, so that all setup options are available.
+ my @plugins=grep { $_ ne $config{rcs} } sort(IkiWiki::listplugins());
+ unshift @plugins, $config{rcs} if $config{rcs}; # rcs plugin 1st
+ foreach my $plugin (@plugins) {
+ eval { IkiWiki::loadplugin($plugin) };
+ if (exists $IkiWiki::hooks{checkconfig}{$plugin}{call}) {
+ my @s=eval { $IkiWiki::hooks{checkconfig}{$plugin}{call}->() };
+ }
+ }
+
+ foreach my $plugin (@plugins) {
+ if (exists $IkiWiki::hooks{getsetup}{$plugin}{call}) {
+ # use an array rather than a hash, to preserve order
+ my @s=eval { $IkiWiki::hooks{getsetup}{$plugin}{call}->() };
+ next unless @s;
+ push @ret, [ $plugin, \@s ],
+ }
+ }
+
+ $config{syslog}=$syslog;
+
+ return @ret;
+}
+
+sub dump ($) {
+ my $file=IkiWiki::possibly_foolish_untaint(shift);
+
+ require IkiWiki::Setup::Standard;
+ my @dump=IkiWiki::Setup::Standard::gendump("Setup file for ikiwiki.");
- exit;
-} #}}}
+ open (OUT, ">", $file) || die "$file: $!";
+ print OUT "$_\n" foreach @dump;
+ close OUT;
+}
1
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki setup automator.
+
+package IkiWiki::Setup::Automator;
+
+use warnings;
+use strict;
+use IkiWiki;
+use IkiWiki::UserInfo;
+use Term::ReadLine;
+use File::Path;
+use Encode;
+
+sub ask ($$) {
+ my ($question, $default)=@_;
+
+ my $r=Term::ReadLine->new("ikiwiki");
+ $r->readline(encode_utf8($question)." ", $default);
+}
+
+sub prettydir ($) {
+ my $dir=shift;
+ $dir=~s/^\Q$ENV{HOME}\E\//~\//;
+ return $dir;
+}
+
+sub import (@) {
+ my $this=shift;
+ IkiWiki::Setup::merge({@_});
+
+ # Sanitize this to avoid problimatic directory names.
+ $config{wikiname}=~s/[^-A-Za-z0-9_]//g;
+ if (! length $config{wikiname}) {
+ error gettext("you must enter a wikiname (that contains alphanumerics)");
+ }
+
+ # Avoid overwriting any existing files.
+ foreach my $key (qw{srcdir destdir repository dumpsetup}) {
+ next unless exists $config{$key};
+ my $add="";
+ my $dir=IkiWiki::dirname($config{$key})."/";
+ my $base=IkiWiki::basename($config{$key});
+ while (-e $dir.$add.$base) {
+ $add=1 if ! $add;
+ $add++;
+ }
+ $config{$key}=$dir.$add.$base;
+ }
+
+ # Set up wrapper
+ if ($config{rcs}) {
+ if ($config{rcs} eq 'git') {
+ $config{git_wrapper}=$config{repository}."/hooks/post-update";
+ }
+ elsif ($config{rcs} eq 'svn') {
+ $config{svn_wrapper}=$config{repository}."/hooks/post-commit";
+ }
+ elsif ($config{rcs} eq 'monotone') {
+ $config{mtn_wrapper}=$config{srcdir}."_MTN/ikiwiki-netsync-hook";
+ }
+ elsif ($config{rcs} eq 'darcs') {
+ $config{darcs_wrapper}=$config{repository}."/_darcs/ikiwiki-wrapper";
+ }
+ elsif ($config{rcs} eq 'bzr') {
+ # TODO
+ }
+ elsif ($config{rcs} eq 'mercurial') {
+ # TODO
+ }
+ else {
+ error sprintf(gettext("unsupported revision control system %s"),
+ $config{rcs});
+ }
+ }
+
+ IkiWiki::checkconfig();
+
+ print "\n\nSetting up $config{wikiname} ...\n";
+
+ # Set up the srcdir.
+ mkpath($config{srcdir}) || die "mkdir $config{srcdir}: $!";
+ # Copy in example wiki.
+ if (exists $config{example}) {
+ # cp -R is POSIX
+ # Another reason not to use -a is so that pages such as blog
+ # posts will not have old creation dates on this new wiki.
+ system("cp -R $IkiWiki::installdir/share/ikiwiki/examples/$config{example}/* $config{srcdir}");
+ delete $config{example};
+ }
+
+ # Set up the repository.
+ delete $config{repository} if ! $config{rcs} || $config{rcs}=~/bzr|mercurial/;
+ if ($config{rcs}) {
+ my @params=($config{rcs}, $config{srcdir});
+ push @params, $config{repository} if exists $config{repository};
+ if (system("ikiwiki-makerepo", @params) != 0) {
+ error gettext("failed to set up the repository with ikiwiki-makerepo");
+ }
+ }
+
+ # Make sure that all the listed plugins can load
+ # and checkconfig is ok. If a plugin fails to work,
+ # remove it from the configuration and keep on truckin'.
+ my %bakconfig=%config; # checkconfig can modify %config so back up
+ if (! eval { IkiWiki::loadplugins(); IkiWiki::checkconfig() }) {
+ foreach my $plugin (@{$config{default_plugins}}, @{$bakconfig{add_plugins}}) {
+ eval {
+ # delete all hooks so that only this plugins's
+ # checkconfig will be run
+ %IkiWiki::hooks=();
+ IkiWiki::loadplugin($plugin);
+ IkiWiki::run_hooks(checkconfig => sub { shift->() });
+ };
+ if ($@) {
+ print STDERR sprintf(gettext("** Disabling plugin %s, since it is failing with this message:"),
+ $plugin)."\n";
+ print STDERR "$@\n";
+ push @{$bakconfig{disable_plugins}}, $plugin;
+ }
+ }
+ }
+ %config=%bakconfig;
+
+ # Generate setup file.
+ require IkiWiki::Setup;
+ IkiWiki::Setup::dump($config{dumpsetup});
+
+ # Build the wiki, but w/o wrappers, so it's not live yet.
+ mkpath($config{destdir}) || die "mkdir $config{destdir}: $!";
+ if (system("ikiwiki", "--refresh", "--setup", $config{dumpsetup}) != 0) {
+ die "ikiwiki --refresh --setup $config{dumpsetup} failed";
+ }
+
+ # Create admin user(s).
+ foreach my $admin (@{$config{adminuser}}) {
+ next if $admin=~/^http\?:\/\//; # openid
+
+ # Prompt for password w/o echo.
+ my ($password, $password2);
+ system('stty -echo 2>/dev/null');
+ local $|=1;
+ print "\n\nCreating wiki admin $admin ...\n";
+ for (;;) {
+ print "Choose a password: ";
+ chomp($password=<STDIN>);
+ print "\n";
+ print "Confirm password: ";
+ chomp($password2=<STDIN>);
+
+ last if $password2 eq $password;
+
+ print "Password mismatch.\n\n";
+ }
+ print "\n\n\n";
+ system('stty sane 2>/dev/null');
+
+ if (IkiWiki::userinfo_setall($admin, { regdate => time }) &&
+ IkiWiki::Plugin::passwordauth::setpassword($admin, $password)) {
+ IkiWiki::userinfo_set($admin, "email", $config{adminemail}) if defined $config{adminemail};
+ }
+ else {
+ error("problem setting up $admin user");
+ }
+ }
+
+ # Add wrappers, make live.
+ if (system("ikiwiki", "--wrappers", "--setup", $config{dumpsetup}) != 0) {
+ die "ikiwiki --wrappers --setup $config{dumpsetup} failed";
+ }
+
+ # Add it to the wikilist.
+ mkpath("$ENV{HOME}/.ikiwiki");
+ open (WIKILIST, ">>$ENV{HOME}/.ikiwiki/wikilist") || die "$ENV{HOME}/.ikiwiki/wikilist: $!";
+ print WIKILIST "$ENV{USER} $config{dumpsetup}\n";
+ close WIKILIST;
+ if (system("ikiwiki-update-wikilist") != 0) {
+ print STDERR "** Failed to add you to the system wikilist file.\n";
+ print STDERR "** (Probably ikiwiki-update-wikilist is not SUID root.)\n";
+ print STDERR "** Your wiki will not be automatically updated when ikiwiki is upgraded.\n";
+ }
+
+ # Done!
+ print "\n\nSuccessfully set up $config{wikiname}:\n";
+ foreach my $key (qw{url srcdir destdir repository}) {
+ next unless exists $config{$key};
+ print "\t$key: ".(" " x (10 - length($key)))." ".
+ prettydir($config{$key})."\n";
+ }
+ print "To modify settings, edit ".prettydir($config{dumpsetup})." and then run:\n";
+ print " ikiwiki -setup ".prettydir($config{dumpsetup})."\n";
+ exit 0;
+}
+
+1
# Parameters to import should be all the standard ikiwiki config stuff,
# plus an array of wrappers to set up.
+package IkiWiki::Setup::Standard;
+
use warnings;
use strict;
-use IkiWiki::Wrapper;
-use IkiWiki::Render;
-
-package IkiWiki::Setup::Standard;
+use IkiWiki;
sub import {
- IkiWiki::setup_standard(@_);
+ IkiWiki::Setup::merge($_[1]);
}
-
-package IkiWiki;
-
-sub setup_standard {
- my %setup=%{$_[1]};
- $setup{plugin}=$config{plugin};
- if (exists $setup{add_plugins}) {
- push @{$setup{plugin}}, @{$setup{add_plugins}};
- delete $setup{add_plugins};
+sub dumpline ($$$$) {
+ my $key=shift;
+ my $value=shift;
+ my $type=shift;
+ my $prefix=shift;
+
+ eval q{use Data::Dumper};
+ error($@) if $@;
+ local $Data::Dumper::Terse=1;
+ local $Data::Dumper::Indent=1;
+ local $Data::Dumper::Pad="\t";
+ local $Data::Dumper::Sortkeys=1;
+ local $Data::Dumper::Quotekeys=0;
+ # only the perl version preserves utf-8 in output
+ local $Data::Dumper::Useperl=1;
+
+ my $dumpedvalue;
+ if (($type eq 'boolean' || $type eq 'integer') && $value=~/^[0-9]+$/) {
+ # avoid quotes
+ $dumpedvalue=$value;
}
- if (exists $setup{exclude}) {
- push @{$config{wiki_file_prune_regexps}}, $setup{exclude};
+ elsif (ref $value eq 'ARRAY' && @$value && ! grep { /[^\S]/ } @$value) {
+ # dump simple array as qw{}
+ $dumpedvalue="[qw{".join(" ", @$value)."}]";
}
-
- if (! $config{render} && (! $config{refresh} || $config{wrappers})) {
- debug(gettext("generating wrappers.."));
- my @wrappers=@{$setup{wrappers}};
- delete $setup{wrappers};
- my %startconfig=(%config);
- foreach my $wrapper (@wrappers) {
- %config=(%startconfig, rebuild => 0, verbose => 0, %setup, %{$wrapper});
- checkconfig();
- if (! $config{cgi} && ! $config{post_commit}) {
- $config{post_commit}=1;
+ else {
+ $dumpedvalue=Dumper($value);
+ chomp $dumpedvalue;
+ if (length $prefix) {
+ # add to second and subsequent lines
+ my @lines=split(/\n/, $dumpedvalue);
+ $dumpedvalue="";
+ for (my $x=0; $x <= $#lines; $x++) {
+ $lines[$x] =~ s/^\t//;
+ $dumpedvalue.="\t".($x ? $prefix : "").$lines[$x]."\n";
}
- gen_wrapper();
}
- %config=(%startconfig);
+ $dumpedvalue=~s/^\t//;
+ chomp $dumpedvalue;
}
- foreach my $c (keys %setup) {
- next if $c eq 'syslog';
- if (defined $setup{$c}) {
- if (! ref $setup{$c}) {
- $config{$c}=possibly_foolish_untaint($setup{$c});
- }
- elsif (ref $setup{$c} eq 'ARRAY') {
- $config{$c}=[map { possibly_foolish_untaint($_) } @{$setup{$c}}]
- }
- elsif (ref $setup{$c} eq 'HASH') {
- foreach my $key (keys %{$setup{$c}}) {
- $config{$c}{$key}=possibly_foolish_untaint($setup{$c}{$key});
- }
- }
+ return "\t$prefix$key => $dumpedvalue,";
+}
+
+sub dumpvalues ($@) {
+ my $setup=shift;
+ my @ret;
+ while (@_) {
+ my $key=shift;
+ my %info=%{shift()};
+
+ next if $key eq "plugin" || $info{type} eq "internal";
+
+ push @ret, "\t# ".$info{description} if exists $info{description};
+
+ if (exists $setup->{$key} && defined $setup->{$key}) {
+ push @ret, dumpline($key, $setup->{$key}, $info{type}, "");
+ delete $setup->{$key};
+ }
+ elsif (exists $info{example}) {
+ push @ret, dumpline($key, $info{example}, $info{type}, "#");
}
else {
- $config{$c}=undef;
+ push @ret, dumpline($key, "", $info{type}, "#");
}
}
-
- if (! $config{refresh}) {
- $config{rebuild}=1;
- }
-
- loadplugins();
- checkconfig();
+ return @ret;
+}
- if ($config{render}) {
- commandline_render();
- }
+sub gendump ($) {
+ my $description=shift;
+ my %setup=(%config);
+ my @ret;
+
+ # disable logging to syslog while dumping
+ $config{syslog}=undef;
- if (! $config{refresh}) {
- debug(gettext("rebuilding wiki.."));
- }
- else {
- debug(gettext("refreshing wiki.."));
+ push @ret, dumpvalues(\%setup, IkiWiki::getsetup());
+ foreach my $pair (IkiWiki::Setup::getsetup()) {
+ my $plugin=$pair->[0];
+ my $setup=$pair->[1];
+ my @values=dumpvalues(\%setup, @{$setup});
+ if (@values) {
+ push @ret, "", "\t# $plugin plugin", @values;
+ }
}
- lockwiki();
- loadindex();
- refresh();
+ unshift @ret,
+ "#!/usr/bin/perl",
+ "# $description",
+ "#",
+ "# Passing this to ikiwiki --setup will make ikiwiki generate",
+ "# wrappers and build the wiki.",
+ "#",
+ "# Remember to re-run ikiwiki --setup any time you edit this file.",
+ "use IkiWiki::Setup::Standard {";
+ push @ret, "}";
- debug(gettext("done"));
- saveindex();
+ return @ret;
}
1
#!/usr/bin/perl
+package IkiWiki;
+
use warnings;
use strict;
use Storable;
use IkiWiki;
-package IkiWiki;
-
-sub userinfo_retrieve () { #{{{
+sub userinfo_retrieve () {
my $userinfo=eval{ Storable::lock_retrieve("$config{wikistatedir}/userdb") };
return $userinfo;
-} #}}}
+}
-sub userinfo_store ($) { #{{{
+sub userinfo_store ($) {
my $userinfo=shift;
my $newfile="$config{wikistatedir}/userdb.new";
}
}
return $ret;
-} #}}}
+}
-sub userinfo_get ($$) { #{{{
+sub userinfo_get ($$) {
my $user=shift;
my $field=shift;
return "";
}
return $userinfo->{$user}->{$field};
-} #}}}
+}
-sub userinfo_set ($$$) { #{{{
+sub userinfo_set ($$$) {
my $user=shift;
my $field=shift;
my $value=shift;
$userinfo->{$user}->{$field}=$value;
return userinfo_store($userinfo);
-} #}}}
+}
-sub userinfo_setall ($$) { #{{{
+sub userinfo_setall ($$) {
my $user=shift;
my $info=shift;
}
$userinfo->{$user}=$info;
return userinfo_store($userinfo);
-} #}}}
+}
-sub is_admin ($) { #{{{
+sub is_admin ($) {
my $user_name=shift;
return grep { $_ eq $user_name } @{$config{adminuser}};
-} #}}}
-
-sub get_banned_users () { #{{{
- my @ret;
- my $userinfo=userinfo_retrieve();
- foreach my $user (keys %{$userinfo}) {
- push @ret, $user if $userinfo->{$user}->{banned};
- }
- return @ret;
-} #}}}
-
-sub set_banned_users (@) { #{{{
- my %banned=map { $_ => 1 } @_;
- my $userinfo=userinfo_retrieve();
- foreach my $user (keys %{$userinfo}) {
- $userinfo->{$user}->{banned} = $banned{$user};
- }
- return userinfo_store($userinfo);
-} #}}}
+}
1
#!/usr/bin/perl
+package IkiWiki;
+
use warnings;
use strict;
-use Cwd q{abs_path};
-use Data::Dumper ;
+use File::Spec;
+use Data::Dumper;
use IkiWiki;
-package IkiWiki;
-
-sub gen_wrapper () { #{{{
- $config{srcdir}=abs_path($config{srcdir});
- $config{destdir}=abs_path($config{destdir});
- my $this=abs_path($0);
+sub gen_wrapper () {
+ $config{srcdir}=File::Spec->rel2abs($config{srcdir});
+ $config{destdir}=File::Spec->rel2abs($config{destdir});
+ my $this=File::Spec->rel2abs($0);
if (! -x $this) {
error(sprintf(gettext("%s doesn't seem to be executable"), $this));
}
my @envsave;
push @envsave, qw{REMOTE_ADDR QUERY_STRING REQUEST_METHOD REQUEST_URI
CONTENT_TYPE CONTENT_LENGTH GATEWAY_INTERFACE
- HTTP_COOKIE REMOTE_USER} if $config{cgi};
+ HTTP_COOKIE REMOTE_USER HTTPS REDIRECT_STATUS
+ REDIRECT_URL} if $config{cgi};
my $envsave="";
foreach my $var (@envsave) {
- $envsave.=<<"EOF"
+ $envsave.=<<"EOF";
if ((s=getenv("$var")))
addenv("$var", s);
EOF
}
-
+
+ my $test_receive="";
+ if ($config{test_receive}) {
+ require IkiWiki::Receive;
+ $test_receive=IkiWiki::Receive::gen_wrapper();
+ }
+
+ my $check_commit_hook="";
+ my $pre_exec="";
+ if ($config{post_commit}) {
+ # Optimise checking !commit_hook_enabled() ,
+ # so that ikiwiki does not have to be started if the
+ # hook is disabled.
+ #
+ # Note that perl's flock may be implemented using fcntl
+ # or lockf on some systems. If so, and if there is no
+ # interop between the locking systems, the true C flock will
+ # always succeed, and this optimisation won't work.
+ # The perl code will later correctly check the lock,
+ # so the right thing will still happen, though without
+ # the benefit of this optimisation.
+ $check_commit_hook=<<"EOF";
+ {
+ int fd=open("$config{wikistatedir}/commitlock", O_CREAT | O_RDWR, 0666);
+ if (fd != -1) {
+ if (flock(fd, LOCK_SH | LOCK_NB) != 0)
+ exit(0);
+ close(fd);
+ }
+ }
+EOF
+ }
+ elsif ($config{cgi}) {
+ # Avoid more than one ikiwiki cgi running at a time by
+ # taking a cgi lock. Since ikiwiki uses several MB of
+ # memory, a pile up of processes could cause thrashing
+ # otherwise. The fd of the lock is stored in
+ # IKIWIKI_CGILOCK_FD so unlockwiki can close it.
+ $pre_exec=<<"EOF";
+ {
+ int fd=open("$config{wikistatedir}/cgilock", O_CREAT | O_RDWR, 0666);
+ if (fd != -1 && flock(fd, LOCK_EX) == 0) {
+ char *fd_s;
+ asprintf(&fd_s, "%i", fd);
+ setenv("IKIWIKI_CGILOCK_FD", fd_s, 1);
+ }
+ }
+EOF
+ }
+
$Data::Dumper::Indent=0; # no newlines
my $configstring=Data::Dumper->Dump([\%config], ['*config']);
$configstring=~s/\\/\\\\/g;
$configstring=~s/"/\\"/g;
$configstring=~s/\n/\\n/g;
- #translators: The first parameter is a filename, and the second is
- #translators: a (probably not translated) error message.
- open(OUT, ">$wrapper.c") || error(sprintf(gettext("failed to write %s: %s"), "$wrapper.c", $!));;
- print OUT <<"EOF";
+ writefile(basename("$wrapper.c"), dirname($wrapper), <<"EOF");
/* A wrapper for ikiwiki, can be safely made suid. */
#include <stdio.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/file.h>
extern char **environ;
-char *newenviron[$#envsave+5];
+char *newenviron[$#envsave+6];
int i=0;
addenv(char *var, char *val) {
}
int main (int argc, char **argv) {
- /* Sanitize environment. */
char *s;
+
+$check_commit_hook
+$test_receive
$envsave
newenviron[i++]="HOME=$ENV{HOME}";
newenviron[i++]="WRAPPED_OPTIONS=$configstring";
exit(1);
}
+$pre_exec
execl("$this", "$this", NULL);
perror("exec $this");
exit(1);
#translators: The parameter is a filename.
printf(gettext("successfully generated %s"), $wrapper);
print "\n";
-} #}}}
+}
1
fi \\
)
+# Additional configurable path variables.
+W3M_CGI_BIN?=$(PREFIX)/lib/w3m/cgi-bin
+
tflag=$(shell if [ -n "$$NOTAINT" ] && [ "$$NOTAINT" != 1 ]; then printf -- "-T"; fi)
-extramodules=$(shell if [ "$$PROFILE" = 1 ]; then printf -- "-d:Profile"; fi)
+extramodules=$(shell if [ "$$PROFILE" = 1 ]; then printf -- "-d:NYTProf"; fi)
ikiwiki.out: ikiwiki.in
./pm_filter $(PREFIX) $(VER) $(PROBABLE_INST_LIB) < ikiwiki.in > ikiwiki.out
chmod +x ikiwiki.out
-extra_build: ikiwiki.out
- $(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -setup docwiki.setup -refresh
+ikiwiki.setup: ikiwiki.out
+ HOME=/home/me $(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -dumpsetup ikiwiki.setup
+
+extra_build: ikiwiki.out ikiwiki.setup docwiki
./mdwn2man ikiwiki 1 doc/usage.mdwn > ikiwiki.man
./mdwn2man ikiwiki-mass-rebuild 8 doc/ikiwiki-mass-rebuild.mdwn > ikiwiki-mass-rebuild.man
./mdwn2man ikiwiki-makerepo 1 doc/ikiwiki-makerepo.mdwn > ikiwiki-makerepo.man
./mdwn2man ikiwiki-transition 1 doc/ikiwiki-transition.mdwn > ikiwiki-transition.man
./mdwn2man ikiwiki-update-wikilist 1 doc/ikiwiki-update-wikilist.mdwn > ikiwiki-update-wikilist.man
- $(MAKE) -C po mo
+ $(MAKE) -C po
+
+docwiki: ikiwiki.out
+ $(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -setup docwiki.setup -refresh
extra_clean:
rm -rf html doc/.ikiwiki
- rm -f *.man ikiwiki.out
- rm -f plugins/*.pyc
+ rm -f *.man ikiwiki.out ikiwiki.setup plugins/*.pyc
$(MAKE) -C po clean
-extra_install:
+underlay_install:
install -d $(DESTDIR)$(PREFIX)/share/ikiwiki
for dir in `cd underlays && find . -follow -type d ! -regex '.*\.svn.*'`; do \
install -d $(DESTDIR)$(PREFIX)/share/ikiwiki/$$dir; \
for file in `find underlays/$$dir -follow -maxdepth 1 -type f`; do \
+ cp -aL $$file $(DESTDIR)$(PREFIX)/share/ikiwiki/$$dir 2>/dev/null || \
install -m 644 $$file $(DESTDIR)$(PREFIX)/share/ikiwiki/$$dir; \
done; \
done
+
+ # The directive docs become their own special underlay.
+ install -d $(DESTDIR)$(PREFIX)/share/ikiwiki/directives/ikiwiki/directive
+ for file in doc/ikiwiki/directive/*; do \
+ if [ -f "$$file" ]; then \
+ install -m 644 $$file $(DESTDIR)$(PREFIX)/share/ikiwiki/directives/ikiwiki/directive; \
+ fi \
+ done
+
+extra_install: underlay_install
+ # Install example sites.
+ for dir in `cd doc/examples; find . -type d ! -regex '.*\.svn.*'`; do \
+ install -d $(DESTDIR)$(PREFIX)/share/ikiwiki/examples/$$dir; \
+ done
+ for file in `cd doc/examples; find . -type f ! -regex '.*\.svn.*'`; do \
+ cp -aL doc/examples/$$file $(DESTDIR)$(PREFIX)/share/ikiwiki/examples/$$file 2>/dev/null || \
+ install -m 644 doc/examples/$$file $(DESTDIR)$(PREFIX)/share/ikiwiki/examples/$$file; \
+ done
+
for dir in `find templates -follow -type d ! -regex '.*\.svn.*'`; do \
install -d $(DESTDIR)$(PREFIX)/share/ikiwiki/$$dir; \
for file in `find $$dir -follow -maxdepth 1 -type f`; do \
done
install -d $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins
- for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\*`; do \
+ for file in `find plugins -maxdepth 1 -type f ! -path plugins/.\* ! -name \*demo\* -name \*.py`; do \
+ install -m 644 $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ done
+ for file in `find plugins -maxdepth 1 -type f ! -path plugins/.\* ! -name \*demo\* ! -name \*.py ! -name \*.pyc`; do \
install -m 755 $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
- done; \
+ done
install -d $(DESTDIR)$(PREFIX)/share/man/man1
install -m 644 ikiwiki.man $(DESTDIR)$(PREFIX)/share/man/man1/ikiwiki.1
install -d $(DESTDIR)$(PREFIX)/sbin
install ikiwiki-mass-rebuild $(DESTDIR)$(PREFIX)/sbin
- install -d $(DESTDIR)$(PREFIX)/lib/w3m/cgi-bin
- install ikiwiki-w3m.cgi $(DESTDIR)$(PREFIX)/lib/w3m/cgi-bin
+ install -d $(DESTDIR)$(W3M_CGI_BIN)
+ install ikiwiki-w3m.cgi $(DESTDIR)$(W3M_CGI_BIN)
install -d $(DESTDIR)$(PREFIX)/bin
install ikiwiki.out $(DESTDIR)$(PREFIX)/bin/ikiwiki
install ikiwiki-makerepo ikiwiki-transition ikiwiki-update-wikilist $(DESTDIR)$(PREFIX)/bin/
$(MAKE) -C po install DESTDIR=$(DESTDIR) PREFIX=$(PREFIX)
+
+ # These might fail if a regular user is installing into a home
+ # directory.
+ -install -d $(DESTDIR)/etc/ikiwiki
+ -install -m 0644 wikilist $(DESTDIR)/etc/ikiwiki
+ -install -m 0644 auto.setup $(DESTDIR)/etc/ikiwiki
+ -install -m 0644 auto-blog.setup $(DESTDIR)/etc/ikiwiki
}
}
PM_FILTER => './pm_filter $(PREFIX) $(VER) $(PROBABLE_INST_LIB)',
MAN1PODS => {},
PREREQ_PM => {
- 'XML::Simple' => 0,
- 'Text::Markdown' => 0,
- 'Date::Parse' => 0,
- 'HTML::Template' => 0,
- 'HTML::Scrubber' => 0,
- 'CGI::FormBuilder' => 3.02.02,
- 'CGI::Session' => 0,
- 'Mail::Sendmail' => 0,
- 'HTML::Parser' => 0,
- 'URI' => 0,
- 'Data::Dumper' => 2.11,
+ 'XML::Simple' => "0",
+ 'Text::Markdown' => "0",
+ 'Date::Parse' => "0",
+ 'HTML::Template' => "0",
+ 'HTML::Scrubber' => "0",
+ 'CGI::FormBuilder' => "3.02.02",
+ 'CGI::Session' => "0",
+ 'Mail::Sendmail' => "0",
+ 'HTML::Parser' => "0",
+ 'URI' => "0",
+ 'Data::Dumper' => "2.11",
},
);
Use ./Makefile.PL to generate a Makefile, "make" will build the
documentation wiki and a man page, and "make install" will install ikiwiki.
+All other documentation is in the ikiwiki documentation wiki, which is also
+available online at <http://ikiwiki.info/>
+
+
A few special variables you can set while using the Makefile:
-PROFILE=1 turns on profiling for the build of the doc wiki. Uses Devel::Profile
+ PROFILE=1 turns on profiling for the build of the doc wiki.
+ (Uses Devel::NYTProf)
-NOTAINT=0 turns on the taint flag in the ikiwiki program. (Not recommended
-unless your perl is less buggy than mine -- see
-http://bugs.debian.org/411786)
+ NOTAINT=0 turns on the taint flag in the ikiwiki program. (Not recommended
+ unless your perl is less buggy than mine -- see
+ http://bugs.debian.org/411786)
-There are also other variables supported by MakeMaker, including PREFIX,
-INSTALL_BASE, and DESTDIR. See ExtUtils::MakeMaker(3).
+ There are also other variables supported by MakeMaker, including PREFIX,
+ INSTALL_BASE, and DESTDIR. See ExtUtils::MakeMaker(3).
-All other documentation is in the ikiwiki documentation wiki, which is also
-available online at <http://ikiwiki.info/>
+ In particular, INSTALL_BASE is very useful if you want to install ikiwiki
+ to some other location, as it configures it to see the perl libraries
+ there. See `doc/tips/nearlyfreespeech.mdwn` for an example of using this to
+ install ikiwiki and its dependencies in a home directory.
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki setup automator -- blog version.
+#
+# This setup file causes ikiwiki to create a wiki, containing a blog,
+# check it into revision control, generate a setup file for the new
+# wiki, and set everything up.
+#
+# Just run: ikiwiki -setup /etc/ikiwiki/auto-blog.setup
+#
+# By default, it asks a few questions, and confines itself to the user's home
+# directory. You can edit it to change what it asks questions about, or to
+# modify the values to use site-specific settings.
+
+require IkiWiki::Setup::Automator;
+
+our $wikiname=IkiWiki::Setup::Automator::ask(
+ gettext("What will the blog be named?"), gettext("blog"));
+our $rcs=IkiWiki::Setup::Automator::ask(
+ gettext("What revision control system to use?"), "git");
+our $admin=IkiWiki::Setup::Automator::ask(
+ gettext("What wiki user (or openid) will be admin?"), $ENV{USER});
+use Net::Domain q{hostfqdn};
+our $domain=hostfqdn() || ikiwiki::setup::automator::ask(
+ gettext("What is the domain name of the web server?"), "");
+
+IkiWiki::Setup::Automator->import(
+ wikiname => $wikiname,
+ adminuser => [$admin],
+ rcs => $rcs,
+ srcdir => "$ENV{HOME}/$wikiname",
+ destdir => "$ENV{HOME}/public_html/$wikiname",
+ repository => "$ENV{HOME}/$wikiname.".($rcs eq "monotone" ? "mtn" : $rcs),
+ dumpsetup => "$ENV{HOME}/$wikiname.setup",
+ url => "http://$domain/~$ENV{USER}/$wikiname",
+ cgiurl => "http://$domain/~$ENV{USER}/$wikiname/ikiwiki.cgi",
+ cgi_wrapper => "$ENV{HOME}/public_html/$wikiname/ikiwiki.cgi",
+ adminemail => "$ENV{USER}\@$domain",
+ add_plugins => [qw{goodstuff websetup comments blogspam}],
+ disable_plugins => [qw{}],
+ libdir => "$ENV{HOME}/.ikiwiki",
+ rss => 1,
+ atom => 1,
+ syslog => 1,
+
+ example => "blog",
+ comments_pagespec => "posts/* and !*/Discussion",
+ blogspam_pagespec => "postcomment(*)",
+ discussion => 0,
+)
--- /dev/null
+#!/usr/bin/perl
+# Ikiwiki setup automator.
+#
+# This setup file causes ikiwiki to create a wiki, check it into revision
+# control, generate a setup file for the new wiki, and set everything up.
+#
+# Just run: ikiwiki -setup /etc/ikiwiki/auto.setup
+#
+# By default, it asks a few questions, and confines itself to the user's home
+# directory. You can edit it to change what it asks questions about, or to
+# modify the values to use site-specific settings.
+
+require IkiWiki::Setup::Automator;
+
+our $wikiname=IkiWiki::Setup::Automator::ask(
+ gettext("What will the wiki be named?"), gettext("wiki"));
+our $rcs=IkiWiki::Setup::Automator::ask(
+ gettext("What revision control system to use?"), "git");
+our $admin=IkiWiki::Setup::Automator::ask(
+ gettext("Which user (wiki account or openid) will be admin?"), $ENV{USER});
+use Net::Domain q{hostfqdn};
+our $domain=hostfqdn() || ikiwiki::setup::automator::ask(
+ gettext("What is the domain name of the web server?"), "");
+
+IkiWiki::Setup::Automator->import(
+ wikiname => $wikiname,
+ adminuser => [$admin],
+ rcs => $rcs,
+ srcdir => "$ENV{HOME}/$wikiname",
+ destdir => "$ENV{HOME}/public_html/$wikiname",
+ repository => "$ENV{HOME}/$wikiname.".($rcs eq "monotone" ? "mtn" : $rcs),
+ dumpsetup => "$ENV{HOME}/$wikiname.setup",
+ url => "http://$domain/~$ENV{USER}/$wikiname",
+ cgiurl => "http://$domain/~$ENV{USER}/$wikiname/ikiwiki.cgi",
+ cgi_wrapper => "$ENV{HOME}/public_html/$wikiname/ikiwiki.cgi",
+ adminemail => "$ENV{USER}\@$domain",
+ add_plugins => [qw{goodstuff websetup}],
+ disable_plugins => [qw{}],
+ libdir => "$ENV{HOME}/.ikiwiki",
+ rss => 1,
+ atom => 1,
+ syslog => 1,
+)
+ikiwiki (3.1415926) UNRELEASED; urgency=low
+
+ In order to fix a performance bug, all wikis need to be rebuilt on
+ upgrade to this version. If you listed your wiki in
+ /etc/ikiwiki/wikilist this will be done automatically when the
+ Debian package is upgraded. Or use ikiwiki-mass-rebuild to force
+ a rebuild.
+
+ -- Joey Hess <joeyh@debian.org> Tue, 25 Aug 2009 17:24:43 -0400
+
+ikiwiki (3.13) unstable; urgency=low
+
+ The `ikiwiki-transition deduplinks` command introduced in the
+ last release was buggy. If you followed the NEWS file instructions
+ and ran it, you should run `ikiwiki -setup` to rebuild your wiki
+ to fix the problem.
+
+ -- Joey Hess <joeyh@debian.org> Fri, 22 May 2009 13:04:02 -0400
+
+ikiwiki (3.12) unstable; urgency=low
+
+ You may want to run `ikiwiki-transition deduplinks your.setup`
+ after upgrading to this version of ikiwiki. This command will
+ optimise your wiki's saved state, removing duplicate information
+ that can slow ikiwiki down.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 06 May 2009 00:25:06 -0400
+
+ikiwiki (3.01) unstable; urgency=low
+
+ If your wiki uses git, and you have a `diffurl` configured in
+ its setup file, you should be aware that gitweb has stopped
+ supporting the url form commonly used for the `diffurl`.
+
+ You can change your setup to use the newer gitweb url form:
+
+ http://git.example.com/gitweb.cgi?p=wiki.git;a=blobdiff;f=[[file]];h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_commit]];hpb=[[sha1_parent]]
+
+ The changes from the old form are the addition of the `hpb` parameter,
+ and the change to the value used for the `hb` parameter.
+
+ -- Joey Hess <joeyh@debian.org> Mon, 05 Jan 2009 18:18:05 -0500
+
+ikiwiki (3.00) unstable; urgency=low
+
+ The 3.0 release of ikiwiki changes several defaults and finishes
+ some transitions. You will need to modify your wikis to work with
+ ikiwiki 3.0. A document explaining the process is available
+ in </usr/share/doc/ikiwiki/html/tips/upgrade_to_3.0.html>
+
+ -- Joey Hess <joeyh@debian.org> Tue, 23 Dec 2008 16:14:18 -0500
+
+ikiwiki (2.62) unstable; urgency=low
+
+ TexImg standard preamble changed
+
+ The teximg plugin now has a configurable LaTeX preamble.
+ As part of this change the `mchem` LaTeX package has been removed from
+ the default LaTeX preamble as it wasn't included in many TeX installations.
+
+ The previous behaviour can be restored by adding the following to your
+ ikiwiki setup:
+
+ teximg_prefix => '\documentclass{scrartcl}
+ \usepackage[version=3]{mhchem}
+ \usepackage{amsmath}
+ \usepackage{amsfonts}
+ \usepackage{amssymb}
+ \pagestyle{empty}
+ \begin{document}',
+
+ In addition, the rendering mechanism has been changed to use `dvipng` by
+ default, if available.
+
+ -- Joey Hess <joeyh@debian.org> Sun, 24 Aug 2008 15:00:40 -0400
+
+ikiwiki (2.60) unstable; urgency=low
+
+ Admin preferences are moving from the web interface to the setup file.
+ There are three new options in the setup file: `locked_pages`, `banned_users`,
+ and `allowed_attachments`. The admin prefs page can still be used, but
+ that's deprecated, and the prefs will be hidden if a value is not already
+ set. If a value is set in the web interface, you're encouraged to move that
+ setting to your setup file now, since version 3.0 will remove the deprecated
+ admin prefs web interface.
+
+ Also, the layout of the setup file has changed in a significant way in this
+ release. Old setup files will continue to work, but new features, like the
+ new websetup interface, require a new format setup file. You can convert
+ old setup files into the new format by running
+ `ikiwiki-transition setupformat ikiwiki.setup`
+
+ -- Joey Hess <joeyh@debian.org> Fri, 01 Aug 2008 17:02:14 -0400
+
ikiwiki (2.52) unstable; urgency=low
All wikis need to be rebuilt on upgrade to this version. If you listed your
in their setup files.
To convert your wiki to the new syntax, ikiwiki provides a new script
- ikiwiki-transition. It will convert preprocessor directives in
- all files given on the command line. To convert an entire wiki:
-
- find wikidir/ -type f -name '*.mdwn' -print0 | xargs -0 ikiwiki-transition prefix_directives
+ ikiwiki-transition.
Even with prefix_directives disabled, ikiwiki now allows an optional '!'
prefix on preprocessor directives (but still requires a space). Thus, a
-ikiwiki (2.53) UNRELEASED; urgency=low
+ikiwiki (3.1415926) UNRELEASED; urgency=low
+
+ * po: Detect if nowrapi18n can't be passed to po4a, and warn about
+ the old version, but continue. Closes: #541205
+ * inline: Avoid use of my $_ as it fails with older perls.
+ Closes: #541215
+ * Add discussionpage configuration setting.
+ * Several optimisations, including speedups to orphans and brokenlinks
+ calculation.
+ * meta, img: Fix bugs in dependency code. (smcv)
+ * Allow building ikiwiki on systems w/o po4a --
+ building of the translated underlays will be skipped in this case.
+ * Add basic styling of po plugin's languages list.
+ * inline: Display an error if feedpages is specified and fails to match
+ due to a problem such as created_before being told to check against
+ a page that does not exist.
+ * Remove deprecated ikiwiki/blog and ikiwiki/preprocessordirective
+ pages from the basewiki.
+ * Updated French program translation from Philippe Batailler.
+ Closes: #542036
+ * po: Fixed to run rcs_add ralative to srcdir.
+ * Italian program translation from Luca Bruno.
+ * Fix example blog's tags/life to not have a broken PageSpec.
+ Closes: #543510
+ * Optimize the dependencies list. This also fixes a bug
+ that could cause repeated refreshes of the wiki to grow
+ increasingly larger dependency lists, and get increasingly
+ slower. (smcv)
+ * Rebuild wikis on upgrade to this version to fix bloat caused
+ by the dependency bug.
+ * htmltidy: Return an error message if tidy fails. Closes: #543722
+ * po: Fix name of translated toplevel index page. (intrigeri)
+ * po: Fix display of links from a translated page to itself (ntrigeri)
+
+ -- Joey Hess <joeyh@debian.org> Wed, 12 Aug 2009 12:25:30 -0400
+
+ikiwiki (3.141592) unstable; urgency=low
+
+ * Add new hooks: canremove, canrename, rename. (intrigeri)
+ * rename: Refactor subpage rename handling code into rename hook. (intrigeri)
+ * po: New plugin<F11>, suporting translation of wiki pages using po files.
+ (intrigeri)
+ * Add build machinery to build po files to translate the underlay wikis,
+ * Add further build machinery to generate translated underlays from
+ the po file, for use by wikis whose primary language is not English.
+ * Add Danish basewiki translation by Jonas Smedegaard.
+ * img: Fix adding of dependency from page to the image.
+ * pagestats: add `among` parameter, which only counts links from specified
+ pages (smcv)
+ * pagestats: when making a tag cloud, don't emit links where the tag is
+ unused (smcv)
+ * map: Avoid emitting an unclosed ul element if the map is empty. (harishcm)
+ * inline: Add pagenames parameter that can be used to list a set of
+ pages to inline, in a specific order, without using a PageSpec. (smcv)
+ * Add getsource plugin (Will, smcv)
+
+ -- Joey Hess <joeyh@debian.org> Tue, 11 Aug 2009 14:59:31 -0400
+
+ikiwiki (3.14159) unstable; urgency=low
+
+ * svn: Fix rcs_rename to properly scope call to dirname.
+ * img: Pass the align parameter through to the generated img tag.
+ * Move OpenID pretty-printing from openid plugin to core (smcv)
+
+ -- Joey Hess <joeyh@debian.org> Thu, 16 Jul 2009 14:37:22 -0400
+
+ikiwiki (3.1415) unstable; urgency=low
+
+ * img: Fix extra double quote with alt text. (smcv)
+ * Updated French debconf templates translation. Closes: #535103
+ * openid: Support Net::OpenID 2.x when pretty-printing
+ openids. (smcv)
+ * highlight: Fix utf-8 encoding bug. Closes: #535028
+
+ -- Joey Hess <joeyh@debian.org> Tue, 07 Jul 2009 16:25:05 -0400
+
+ikiwiki (3.141) unstable; urgency=low
+
+ * comment: Make comment directives no longer use the internal "_comment"
+ form, and document the comment directive syntax.
+ * Avoid relying on translators preserving the case when translating
+ "discussion", which caused Discussion pages to get unwanted Discussion
+ links.
+ * Tighten up matching of bare words inside directives; do not
+ allow an unterminated """ string to be treated as a series
+ of bare words. Fixes runaway regexp recursion/backtracking
+ in strange situations.
+ * Setup automator: Check that each plugin added to the generated
+ setup file can be loaded and that its config is ok. If a plugin
+ fails for any reason, disable it in the generated file.
+ Closes: 532001
+ * pagecount: Fix broken optimisation for * pagespec.
+ * goto: Support being passed a page title that is not a valid page
+ name, to support several cases including mercurial's long user
+ names on the RecentChanges page, and urls with spaces being handled
+ by the 404 plugin.
+ * Optimise use of gettext, and avoid ugly warnings if Locale::gettext
+ is not available. Closes: #532285
+ * meta: Add openid delegate parameter to allow delegating only
+ openid or openid2.
+ * Disable the Preferences link if no plugin with an auth hook is enabled.
+ * Updated French translation. Closes: #532654
+ * aggregate: Fix storing of changed md5.
+ * aggregate: Avoid resetting ctime when an item md5 changes.
+
+ -- Joey Hess <joeyh@debian.org> Fri, 12 Jun 2009 19:50:46 -0400
+
+ikiwiki (3.14) unstable; urgency=low
+
+ * highlight: New plugin supporting syntax highlighting of pretty much
+ anything.
+ * debian/control: Add suggests for libhighlight-perl, although
+ that package is not yet created by Debian's highlight source package.
+ (See #529869)
+ * format: Provide a htmlizefallback hook that other plugins
+ can use to handle formats that are not suitable for general-purpose
+ htmlize hooks. Used by highlight.
+ * Fix test suite to not rely on an installed copy of ikiwiki after
+ underlaydir change. Closes: #530502
+ * Danish translation update. Closes: #530877
+
+ -- Joey Hess <joeyh@debian.org> Mon, 01 Jun 2009 13:05:34 -0400
+
+ikiwiki (3.13) unstable; urgency=low
+
+ * ikiwiki-transition: If passed a nonexistant srcdir, or one not
+ containing .ikiwiki, abort with an error rather than creating it.
+ * Allow underlaydir to be overridden without messing up inclusion
+ of other underlays via add_underlay.
+ * More friendly display of markdown, textile in edit form selector
+ (jmtd)
+ * Allow curly braces to be used in pagespecs, and avoid a whole class
+ of potential security problems, by avoiding performing any string
+ interpolation on user-supplied data when translating pagespecs.
+ * ikiwiki-transition: Allow setup files to be passed to all subcommands
+ that need a srcdir.
+ * ikiwiki-transition: deduplinks was broken and threw away all
+ metadata stored by plugins in the index. Fix this bug.
+ * listdirectives: Avoid listing _comment directives and generally
+ assume any directive starting with _ is likewise internal.
+
+ -- Joey Hess <joeyh@debian.org> Fri, 22 May 2009 14:10:56 -0400
+
+ikiwiki (3.12) unstable; urgency=low
+
+ * Re-enable python-support and add python:Depends to control file.
+ * ikiwiki-makerepo: Avoid using abs_path, as it apparently
+ fails on nonexistant directories with some broken perl
+ versions.
+ * inline: Minor optimisation.
+ * add_link: New function, which plugins should use rather than
+ modifying %links directly, to avoid it accumulating duplicates.
+ * ikiwiki-transition: Add a deduplinks action, that can be used
+ to remove duplicate links and optimise a wiki w/o rebuilding it.
+ * external: Fix pagespec_match and pagespec_match_list.
+ Closes: #527281
+
+ -- Joey Hess <joeyh@debian.org> Wed, 06 May 2009 00:31:16 -0400
+
+ikiwiki (3.11) unstable; urgency=low
+
+ * Avoid using python-support. Closes: #525086
+ * websetup: Display stderr in browser if ikiwiki setup fails.
+ * blogspam: Load RPC::XML library in checkconfig, so that an
+ error can be printed at that point if it's not available,
+ allowing the admin to see it during wiki setup.
+ Closes: #520015
+ * websetup: If setup fails, restore old setup file.
+ * relativedate: Deal with clock skew.
+ * Add IkiWiki::ErrorReason objects, and modify pagespecs to return
+ them in cases where they fail to match due to a configuration or syntax
+ error.
+ * pagespec_match_list: New API function, matches pages in a list
+ and throws an error if the pagespec is bad.
+ * inline, brokenlinks, calendar, linkmap, map, orphans, pagecount,
+ pagestate, postsparkline: Display a handy error message if the pagespec
+ is erronious.
+ * comments: Add link to comment post form to allow user to sign in
+ if they wish to, if the configuration makes signin optional
+ for commenting.
+ * Updated Danish translation from Jonas Smedegaard. Closes: #525751
+ * translation.mdwn: Typo fixes. Closes: #525753
+
+ -- Joey Hess <joeyh@debian.org> Mon, 04 May 2009 15:45:10 -0400
+
+ikiwiki (3.10) unstable; urgency=low
+
+ * darcs: Finally added support for this VCS, thanks to many
+ contributors:
+ - Thomas Schwinge wrote the original file, implementing only rcs_commit.
+ - Benjamin A'Lee contributed an alternative implementation.
+ - Tuomo Valkonen contributed rcs_getctime and stub rcs_recentchanges.
+ - Simon Michael contributed multiple changes.
+ - Petr Ročkai fixed rcs_recentchanges.
+ - Sven M. Hallberg merged the above and added missing features.
+ * Add missing newline to Confirm Password prompt.
+ * Add missing permalink support to archivepage and titlepage templates.
+ * debian/control: Wrap fields.
+ * inline: Add author info to archive display.
+ * Add a microblog template that is useful for inlining microblogging posts.
+
+ -- Joey Hess <joeyh@debian.org> Sat, 18 Apr 2009 19:40:25 -0400
+
+ikiwiki (3.09) unstable; urgency=low
+
+ * inline: Add title_natural sort order, using Sort::Naturally
+ (chrysn)
+ * inline: Fix urls to feed when feedfile is used on an index page.
+ * git, mercurial: Fix --getctime to return file creation time,
+ not last commit time.
+ * Updated French translation (Jean-Luc Coulon). Closes: #521072
+ * css: Add clear: both to inlinefooter.
+ * comments: Fix too loose test for comments pages that matched
+ normal pages with "comment_" in their name. Closes: #521322
+ * comments: Fix anchor ids to be legal xhtml. Closes: #521339
+ * Fix documentation of anonok_pagespec. Closes: #521793
+ * Add missing suggests on libtext-textile-perl. Closes: #522039
+ * recentchanges: change to using do=goto links for user links.
+ * Fix git test suite to use a bare repo.
+
+ -- Joey Hess <joeyh@debian.org> Sat, 04 Apr 2009 14:33:49 -0400
+
+ikiwiki (3.08) unstable; urgency=low
+
+ * git: Fix utf-8 encoding of author names.
+ * git: Manually decode git output from utf-8, avoids
+ warning messages on invalidly encoded output.
+ * Fix bug that caused weird things to appear as page types.
+
+ -- Joey Hess <joeyh@debian.org> Sun, 15 Mar 2009 17:54:47 -0400
+
+ikiwiki (3.07) unstable; urgency=low
+
+ * Updated German translation (Kai Wasserbäch). Closes: #518377
+ * Updated French translation (Jean-Luc Coulon). Closes: #518510
+ * wmd: New plugin contributed by William Uther to support the WMD
+ Wysiwym markdown editor.
+ * smiley: Avoid infinite loop in smiley expansion triggered
+ by the template scan mode change in version 3.05. Closes: #518805
+ * template: When loading a template in scan mode, let preprocess
+ know it only needs to scan.
+
+ -- Joey Hess <joeyh@debian.org> Sun, 08 Mar 2009 19:00:46 -0400
+
+ikiwiki (3.06) unstable; urgency=low
+
+ * Setup automator: Fix bug in password comparison. Closes: #517654
+
+ -- Joey Hess <joeyh@debian.org> Sun, 01 Mar 2009 15:02:30 -0500
+
+ikiwiki (3.05) unstable; urgency=low
+
+ * debhelper v7(.0.50); rules file minimisation.
+ * template: Load templates in scan mode.
+ This is potentially expensive, but is necessary so that meta and tag
+ directives, and other links on templates affect the page using the
+ template reliably.
+ * goto: Fix redirect to comments.
+ * Add noextension parameter to htmlize hooks to support, eg, Makefile.
+ * Add tagged() PageSpec.
+ * Updated German translation (Kai Wasserbäch). Closes: #516770
+ * Setup automator: Prompt for password twice. Closes: #516973
+ * bzr: Add missing rcs_diff. (liw)
+ * comments: Avoid showing comment moderation button in prefs to non-admins.
+ * goto: Fix typo that broke recentchanges_link compatibility.
+
+ -- Joey Hess <joeyh@debian.org> Fri, 27 Feb 2009 15:48:39 -0500
+
+ikiwiki (3.04) unstable; urgency=low
+
+ * 404: New plugin which lets you use the IkiWiki CGI script as
+ an Apache 404 handler, to give the behaviour of various other wiki
+ engines where visiting a nonexistent page provides you with a link
+ to create it. (smcv)
+ * Factor out redundant code into goto plugin. (smcv)
+ * Work around XML::Atom strangeness that results in double-encoded posts.
+ (smcv)
+ * Fix unusual --setup --post-commit command line option combo.
+ * Create any missing directory necessary to put the wrapper
+ file into. Closes: #514384
+ * shortcut: If default_pageext is set, first look for
+ shortcuts.default_pageext.
+ * Allow comments, rename, remove, and attachment plugins to be used
+ even if the editpage plugin is disabled.
+
+ -- Joey Hess <joeyh@debian.org> Sat, 14 Feb 2009 02:27:14 -0500
+
+ikiwiki (3.03) unstable; urgency=low
+
+ * Avoid feeding decoded unicode to Term::ReadLine. Closes: 512169
+ * blogspam: Log spam info on failure in debug mode.
+ * Remove nonstandard css. Closes: #512378
+ * blogspam: Fix use of blogspam_options and blogspam_server config settings.
+ * comments: If comment content checks fail, store the comment
+ (in .ikiwiki/comments_pending) for moderator review.
+ * comments: Add a moderation web interface, which admins can
+ access via their Preferences page.
+ * git: Fix malformed utf8 received from git.
+ * meta: New "updated" metadata specifies a fake modification time for a
+ page, to be output into RSS and Atom feeds. (smcv)
+ * underlay: New plugin, allows pulling in additional files not
+ in version control. (smcv)
+
+ -- Joey Hess <joeyh@debian.org> Thu, 29 Jan 2009 14:36:58 -0500
+
+ikiwiki (3.02) unstable; urgency=low
+
+ * blogspam: New plugin, adding spam filtering for page editing / comment
+ posting using the BlogSpam.net API.
+ * Add auto-blog.setup, which will set up an ikiwiki instance tuned for use
+ in blogging.
+ * checkcontent: New hook, can be used to implement arbitrary content
+ filters, including spam filters.
+ * table: Fix misparsed links in external files.
+ * table: Find links in external files in scan pass.
+ * rename: Show full names of affected pages.
+ * comments: Fix cache avoidance hack.
+ * repolist: New plugin to support the rel=vcs-* microformat.
+ * goodstuff: Include repolist by default. (But it does nothing until
+ configured with the repository locations.)
+ * comments: Add support for removing comments via web interface. (smcv)
+ * Consistently allow use of relative paths in all PageSpecs
+ that take a page name parameter. Previously, match_created_before(),
+ match_created_after(), match_sourcepage(), and match_destpage()
+ did not support that, and the docs were not clear.
+ * pinger: Get whole url, don't just head, avoids problems on
+ the nostromo web server.
+ * Recommend libterm-readline-gnu-perl since that makes auto.setup
+ behave better.
+
+ -- Joey Hess <joeyh@debian.org> Sat, 17 Jan 2009 18:19:39 -0500
+
+ikiwiki (3.01) unstable; urgency=low
+
+ * ikiwiki-makerepo: Fix injecting of empty mercurial and bzr repositories.
+ Closes: #510518
+ * Fix documentation about git hook to use right name. Closes: #510393
+ * yesno: Always accept English even when localised.
+ * yesno: Also accept 1 and 0 as input.
+ * A recent change to gitweb removed support for the form of diffurl
+ that many ikiwiki setups use. Document how to use the new url form.
+
+ -- Joey Hess <joeyh@debian.org> Mon, 05 Jan 2009 18:53:50 -0500
+
+ikiwiki (3.00) unstable; urgency=low
+
+ * Remove support for GlobLists.
+ * Remove support for configuring allowed attachments, locked pages,
+ and banned users from the admin preferences page. These can only be
+ controlled via the setup file now.
+ * ikiwiki-transition moveprefs can be used to move the above
+ admin preferences into a setup file.
+ * prefix_directives and aggregate_internal are now turned on by default.
+ * ikiwiki-transition prefix_directives syntax changed
+ * googlecalendar: removed this deprecated plugin. Use htmlscrubber_skip
+ instead.
+ * embed: This plugin is deprecated, use htmlscrubber_skip instead.
+ Closes: ##462970.
+ * Version 3.00 of the plugin API.
+ * Replace blank OpenID placeholder logo with an unofficial OpenID
+ logo developed by Anna Hess. The official logo does not seem destined to
+ be free.
+ * comments: Add cache avoidance.
+ * htmlbalance: Demand-load HTML::TreeBuilder to avoid failing test suite
+ if it is not present.
+ * French translation update from Philippe Batailler. Closes: #510216
+ * websetup: Avoid a crash when a new array setup item has been added in
+ a new ikiwiki release, and is thus not present in the setup file yet.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 31 Dec 2008 15:17:47 -0500
+
+ikiwiki (2.72) unstable; urgency=low
+
+ * Avoid comments in recentchanges being broken links (smcv)
+ * Add deprecation warning for GlobLists, which will stop working in 3.0.
+ * camelcase: Add camelcase_ignore setting.
+ * googlecalendar: Add runtime deprecation warning.
+ * comments: Deal with users entering unqualified or partial urls.
+ * inline: Run format hook first, to ensure other format hooks can affect
+ inlined content. Closes: #509710
+
+ -- Joey Hess <joeyh@debian.org> Sun, 28 Dec 2008 15:01:02 -0500
+
+ikiwiki (2.71) unstable; urgency=low
+
+ * comments: Blog-style comment support, contributed by Simon McVittie.
+ * htmlbalance: New plugin contributed by Simon McVittie.
+ * Change deb dependencies to list Text::Markdown before markdown (really
+ this time).
+ * Improve escaping of wikilinks and preprocessor directives in content
+ produced by aggregate and recentchanges.
+ * French translation update from Philippe Batailler. Closes: #506250
+ * Spanish translation update from Victor Moral.
+ * Fix handling of wrappergroup option.
+ * Correct --dumpsetup to include the srcdir in the setup file.
+ * German translation update from Kai Wasserbäch. Closes: #507056
+ * inline: Support emptyfeeds=no option to skip generating empty feeds.
+ * inline: Support feedfile option to change the filename of the feed
+ generated.
+ * meta: Pass info to htmlscrubber so htmlscrubber_skip can take effect.
+ * htmlbalance: don't compact whitespace, and set misc other options (smcv)
+ * rename: Fix double-escaping of page name in edit box.
+ * monotone: When getting the log, tell monotone how many entries
+ we want, rather than closing the pipe, which it dislikes. (thm)
+ * Coding style change: Remove explcit vim folding markers.
+ * aggregate: If a feed fails to be downloaded, try again immediatly
+ next time aggregation is run, even if the usual time has not passed.
+ Closes: #508622 (Michael Gold)
+ * meta: Process meta date during scan pass so that the date will always
+ affect sorting in inlines.
+ * Improve display of some openids (smcv)
+
+ -- Joey Hess <joeyh@debian.org> Sun, 21 Dec 2008 16:22:05 -0500
+
+ikiwiki (2.70) unstable; urgency=low
+
+ * Avoid crash on malformed utf-8 discovered by intrigeri.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 12 Nov 2008 17:45:58 -0500
+
+ikiwiki (2.69) unstable; urgency=low
+
+ * Avoid multiple ikiwiki cgi processes piling up, eating all memory,
+ and thrashing, by making the cgi wrapper wait on a cgilock.
+ If you had to set apache's MaxClients low to avoid ikiwiki thrashing your
+ server, you can now turn it up to a high value.
+ * Stop busy-waiting in lockwiki, as this could delay ikiwiki from waking up
+ for up to one second. The bailout code is no longer needed after above
+ change.
+ * Remove support for unused optional wait parameter from lockwiki.
+ * aggregate: Try to query XML::Feed for the base url when derelevatising
+ links. Since this needs the just released XML::Feed 0.3, as well
+ as a not yet released XML::RSS, it will fall back to the old method
+ if no xml:base info is available.
+ * meta: Plugin is now enabled by default since the basewiki uses it.
+ * txt: Do not encode quotes when filtering the txt, as that broke
+ later parsing of any directives on the page.
+ * Fix the link() pagespec to match links that are internally recorded as
+ absolute.
+ * Add rel=nofollow to recentchanges_links for the same (weak) reasons it
+ was earlier added to edit links.
+ * tag: Normalize tagbase so leading/trailing slashes in it don't break
+ things.
+ * bzr: Fix dates for recentchanges.
+
+ -- Joey Hess <joeyh@debian.org> Tue, 11 Nov 2008 20:35:55 -0500
+
+ikiwiki (2.68) unstable; urgency=low
+
+ * Add support for checking pushes from untrusted git committers. This can be
+ used to set up anonymous git pushes, and other similar things.
+ * format: New plugin, allows embedding differently formatted text inside a
+ page (ie, otl inside a mdwn page, or syntax highlighted code inside a
+ page).
+ * relativedate: New javascript-alicious plugin that makes all dates display
+ relative, in a very nice way, if I say so myself.
+ * Optimise the no-op post-commit hook, to speed up web edits by a fraction
+ of a second.
+ * git: Allow [[sha1_commit]] to be used in the diffurl, to support cgit.
+ * shortcut: Fix display of shortcuts while previewing.
+ * Plugins that used to override displaytime should instead override
+ formattime. displaytime will call that, and may wrap markup around the
+ formatted time.
+ * Add an underlay for javascript, and add ikiwiki.js containing some utility
+ code.
+ * toggle: Stop embedding the full toggle code on each page using it, and
+ move it to toggle.js in the javascript underlay.
+ * recentchanges: Make feed links point back to anchors on the recentchanges
+ page. (JasonBlevins)
+ * Fix issue with utf-8 in wikiname breaking session cookies, by
+ entity-encoding the wikiname in the session cookie.
+ * Use the pure perl Data::Dumper when generating setup files to ensure that
+ utf-8 characters are written out as such, and not as the encoded perl
+ strings the C Data::Dumper produces.
+ * inline: Only the last feed link was put on the page, fix this to include
+ all feed links. So rss will be included along with atom, and pages with
+ multiple feeds will get links added for all feeds.
+ * tag: When tagbase is set, force the links created by tagging to point at
+ the toplevel tagbase, and not closer subpages. The html links already went
+ there, but internally the links were not recorded as absolute, which could
+ cause confusing backlinks etc.
+ * Add an inject function, that can be used by plugins that want to
+ replace one of ikiwiki's functions with their own version.
+ (This is a scary thing that grubs through the symbol table, and replaces
+ all exported occurances of a function with the injected version.)
+ * external: RPC functions can be injected to replace exported functions.
+ * Updated French translation. Closes: #502694
+ * Updated Spanish translation from the ever vigilant Victor Moral.
+ * Updated Danish translation from Jonas Smedegaard. Closes: #503117
+ * Preserve syslog setting when doing `ikiwiki -setup foo -dumpsetup bar`
+ * Several fixes to --render mode.
+
+ -- Joey Hess <joeyh@debian.org> Mon, 03 Nov 2008 16:31:11 -0500
+
+ikiwiki (2.67) unstable; urgency=low
+
+ * remove: Avoid $_ breakage. (Stupid, stupid perl.)
+ * Updated Spanish translation from Victor Moral.
+ * lockedit: Support specifying which users (and IP addresses) a page
+ is locked for. This supports most of the ACL type things users have been
+ wanting to be done. Closes: #443346 (It does not control who can read a
+ page, but that's out of scope for ikiwiki.)
+ * orphans: Fix unquoted page name in regexp.
+ * google: Plugin provides google site search, contributed by Peter Simons.
+ * Pass HTTPS variable through the wrapper so that CGI->https can be used
+ by plugins. Closes: #502047
+ * inline: Allow MTIME to be used in inlinepage.tmpl.
+ * inline: Use the feed's description in the rss and atom links.
+ Closes: #502113
+ * aggregate: Avoid bug that caused immediate expiration of items
+ with a date in the future.
+
+ -- Joey Hess <joeyh@debian.org> Fri, 17 Oct 2008 13:13:41 -0400
+
+ikiwiki (2.66) unstable; urgency=low
+
+ * recentchanges: Fix redirects to non-page files.
+ * aggregate: Avoid uninitialized value warnings for pages with no recorded
+ ctime.
+ * attachment: Add admin() pagespec to test if the uploading user is a wiki
+ admin.
+ * git: Fix handling of utf-8 filenames in recentchanges.
+ * tag: Make edit link for new tags ensure that the tags are created
+ inside tagbase, when it's set.
+ * template: Make edit link for new templates ensure the page is located
+ under toplevel templates directory.
+ * htmlscrubber: Add a config setting that can be used to disable the
+ scrubber acting on a set of pages.
+ * Expand usage message and add --help. Closes: #500344
+ * Beautify urls used in various places. (smcv)
+ * Export pagetitle, titlepage, linkpage.
+ * htmltidy: Avoid returning undef if tidy fails. Also avoid returning the
+ untidied content if tidy crashes. In either case, it seems best to tidy
+ the content to nothing.
+ * htmltidy: Avoid spewing tidy errors to stderr.
+ * Reorganize index file, add a format version field. Upgrades to the new
+ index format should be transparent.
+ * Add %wikistate, which is like %pagestate except not specific to a given
+ page, and is preserved across rebuilds.
+ * editpage: Be more aggressive (and less buggy) about cleaning up
+ temporary files rendered during page preview.
+ * Add an indexpages option, which causes foo/index.mdwn to be the source
+ for page foo when foo.mdwn doesn't exist. Also, when it's enabled,
+ creating a new page will save it to foo/index.mdwn by default.
+ Closes: #474611
+ (Sponsored by The TOVA Company.)
+ * httpauth: Document that ikiwiki.cgi has to be in a directory subject to
+ authentication. Closes: #500524
+ * inline: Fix handling of rootpage that doesn't exist.
+ * attachment: Support adding attachments to pages even as they are being
+ created.
+ * remove, rename: Allow acting on attachments as a page is being created.
+ * Updated French translation. Closes: #500929
+
+ -- Joey Hess <joeyh@debian.org> Sun, 05 Oct 2008 19:11:08 -0400
+
+ikiwiki (2.65) unstable; urgency=low
+
+ * aggregate: Expire excess or old items on the same pass that adds them,
+ not only on subsequent passes.
+ * editdiff: Broken since 2.62 due to wrong syntax, now fixed.
+ * aggregate: Support atom feeds with only a summary element, and no content
+ elements.
+ * progress: Display an error if the progress cannot be parsed, and allow
+ the percent parameter to only optionally end with "%".
+ * Fix reversion in use of ikiwiki -verbose -setup with a setup file that
+ enables syslog. Setup output is once again output to stdout in this
+ case.
+ * edittemplate: Default new page file type to the same type as the template.
+ (willu)
+ * edittemplate: Add "silent" parameter. (Willu)
+ * edittemplate: Link to template, to allow creating it. (Willu)
+ * editpage: Add a missing check that the page name contains only legal
+ characters, in addition to the existing check for pruned filenames.
+ * Print a debug message if a page has multiple source files.
+ * Add keepextension parameter to htmlize hook. (Willu)
+ * rename, remove: Don't rely on a form parameter to tell whether the page
+ should be treated as an attachment.
+ * rename: Add support for moving SubPages of a page when renaming it.
+ (Sponsored by The TOVA Company.)
+ * rename: Hide type field from rename form when renaming attachments.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 24 Sep 2008 17:55:14 -0400
+
+ikiwiki (2.64) unstable; urgency=low
+
+ * Avoid uninitialised value when --dumpsetup is used and no srcdir/destdir
+ specified.
+ * ddate: Stop clobbering timeformat when not enabled.
+ * progress: New plugin to generate progress bars (willu)
+ * Add allow_symlinks_before_srcdir to config so websetup doesn't eat it.
+ * img: Support sizes like 200x. Closes: #475149
+ * goodstuff: Remove otl plugin from the bundle since it needs a significant
+ external dependency and is not commonly used. If you use otl, make sure
+ you explicitly enable it now.
+ * goodstuff: Add more, progress, and table plugins to the bundle.
+ * Improve error message if external plugin fails to load. Closes: #498458
+ * Directive documentation broken out of the plugin documentation and into
+ pages suitable to be used as an underlay. Thanks to Willu for doing most
+ of the tedious work.
+ * Move the directive documentation into its own underlay, separate from
+ basewiki, since it's sorta large compared to the rest of basewiki.
+ * listdirectives: Enable use of the directives underlay.
+ * Removed the obsolete blog page from the basewiki. ikiwiki/blog still
+ remains, but is now deprecated too.
+ * Removed old redirecton pages from basewiki (helponformatting,
+ markdown, openid, pagespec, preprocessordirective, subpage, wikilink).
+ * inline: Treat rootpage as a link, so that it can refer to a subpage
+ without hardcoding the path.
+
+ -- Joey Hess <joeyh@debian.org> Sun, 14 Sep 2008 16:58:25 -0400
+
+ikiwiki (2.63) unstable; urgency=low
+
+ * Set cookies HttpOnly.
+ * Typo. Closes: #497003
+ * Ignore failure to install files into /etc, in case install is running as
+ non-root.
+ * Work around perl $_ scoping nonsense that caused breakage when loading
+ external plugins.
+ * style.css: Add missing semicolon. Closes: #497176
+ * filecheck: Fall back to testing for binary or plain text files
+ if no mime type is detected.
+ * table: Support header=column to make the table header be the first
+ column of the data. (AlexandreDupas)
+ * For fine control over what characters are allowed, unescaped in
+ source filenames, the wiki_file_chars setting is added. For example,
+ set to "-[:alnum:]+/._" to disable colons from being used in source files
+ (which can cause troubl om Windows).
+ * po/Makefile: update po files when the pot file has changed.
+ Closes: #497951
+ * editpage: New core plugin factoring out page editing to allow disabling it
+ if desired.
+
+ -- Joey Hess <joeyh@debian.org> Mon, 08 Sep 2008 12:17:15 -0400
+
+ikiwiki (2.62.1) unstable; urgency=low
+
+ * filecheck: Fixed two bits broken in move from attachment.
+
+ -- Joey Hess <joeyh@debian.org> Thu, 28 Aug 2008 13:04:47 -0400
+
+ikiwiki (2.62) unstable; urgency=low
+
+ * Avoid using cp -a (again). (HenrikBrixAndersen)
+ * Avoid using hostname -f for portability to eg, OS X, use Net::Domain
+ instead, and prompt if it fails.
+ * Fix bug in wikiname sanitisation in the setup automator.
+ * ikiwiki-makerepo: Added support for monotone. (Thomas Keller)
+ * map: The fix for #449285 was buggy and broke display of parents in certain
+ circumstances.
+ * teximg: The prefix is configurable, and has changed to not include the
+ nonstandard mhchem by default. (willu)
+ * teximg: dvipng is used if available to render images. Its output is
+ antialiased and better than dvips. If not available, the old dvips+convert
+ chain will be used. (willu)
+ * Drop suggests on texlive-science, add suggests on dvipng.
+ * listdirectives: New plugin. (willu)
+ * filecheck: New plugin factoring out the PageSpec additions that were
+ originally part of the attachment plugin.
+ * edittemplate: Don't wipe out edits on preview.
+ * color: New plugin from ptecza.
+ * autoindex: Avoid re-adding previously deleted (or renamed) pages.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 27 Aug 2008 15:14:09 -0400
+
+ikiwiki (2.61) unstable; urgency=low
+
+ * poll: Fix typo that broke plugin.
+ * graphviz: Fix breakage of the name of the preprocessor directive.
+
+ -- Joey Hess <joeyh@debian.org> Thu, 14 Aug 2008 18:13:22 -0400
+
+ikiwiki (2.60) unstable; urgency=low
+
+ [ Joey Hess ]
+ * Starting with this version, "ikiwiki -setup /etc/ikiwiki/auto.setup"
+ can be used create a new wiki in seconds.
+ * websetup: New plugin providing a setup form on the web.
+ * ikiwiki --dumpsetup can generate a nice setup file snapshotting ikiwiki's
+ current configuration.
+ * The way wrappers are defined in the setup file has changed. Old setup
+ files will continue to work, for now.
+ * ikiwiki-transition setupformat can be used to convert a setup file to the
+ new format.
+ * Version control backends promoted to first-class plugins.
+ * ikiwiki-update-wikilist: Add -r switch to remove. Default behavior is now
+ always to add.
+ * Start moving admin preferences from the web interface to the setup file.
+ * Add getsetup hook, all plugins should use it to record information about
+ themselves and any fields they add to %config
+ * Large amounts of internal config data reorg.
+ * ikiwiki-makerepo: Bail if both srcdir and repository are not specified.
+ Closes: #493628
+ * Clarify some wording in the setup documentation that could maybe lead
+ users to putting paths with "~/" in the setup file, which doesn't work.
+ Closes: #493835
+ * autoindex: Ignore internal pages, and take underlay directories into
+ account. Also, avoid making index pages for directories that contain
+ no files.
+ * external: Fix support for hooks called in an array context.
+ * Options set in the setup file are now immediatly loaded by ikiwiki -setup.
+ This allows later switches to override them. Previously, setup file
+ options overrode most command line options.
+ * Added a small icon to the search input box.
+
+ [ Josh Triplett ]
+ * Add Suggests on texlive and texlive-science for the teximg plugin
+
+ [ Joey Hess ]
+ * inline: Ignore parent dirs when sorting pages by title.
+ * rename: Support changing page extensions. (willu)
+ * Danish update. Closes: #494632
+
+ -- Joey Hess <joeyh@debian.org> Tue, 12 Aug 2008 14:20:25 -0400
+
+ikiwiki (2.56) unstable; urgency=low
+
+ * autoindex: New plugin that generates missing index pages.
+ (Sponsored by The TOVA Company.)
+ * Escape HTML is rss and atom feeds instead of respectively using CDATA and
+ treating it as XHTML. This avoids problems with escaping the end of the
+ CDATA when the htmlscrubber is not used, and it avoids problems with atom
+ XHTML using named entity references that are not in the atom DTD.
+ (Simon McVittie)
+ * Add test for old versions of git that don't support --cleanup=verbatim,
+ and munge empty commit messages.
+
+ -- Joey Hess <joeyh@debian.org> Thu, 31 Jul 2008 19:25:24 -0400
+
+ikiwiki (2.55) unstable; urgency=low
+
+ * remove: New plugin that adds the ability to remove pages via the web.
+ (Sponsored by The TOVA Company.)
+ * rename: New plugin that adds the ability to rename pages via the web.
+ (Sponsored by The TOVA Company.) (This one's for you, Kyle.)
+ * All rcs backends need to implement rcs_remove, rcs_commitstaged,
+ and rcs_rename. (Done for svn, git).
+ * This version adds renamepage hooks, which can be used to modify page
+ content, including links, during renames.
+ * prefix_directives enabled in doc wiki, all preprocessor directives
+ converted. (Simon McVittie)
+ * editpage: Don't show attachments link when attachments are disabled.
+ * tag: Allow tagbase to be overridden by starting a tag with "./" or "/".
+ (Simon McVittie)
+ * Really fix bug with links to pages with names containing colons.
+ Previous fix mised a few cases.
+ * Avoid troublesome abs_path calls in wrapper setup.
+ * Add allow_symlinks_before_srcdir config setting that can be used to avoid
+ a security check that is a good safe default, but problimatic overkill in
+ some situations.
+ * Don't allow uploading an attachment with the same name as an existing
+ page, to avoid confusion.
+ * Split out error messages from editpage.tmpl into several separate
+ templates.
+ * attachment: Do not escape _ when determining attachment filenames.
+ * Rebuild pages that change their type. (Gabriel McManus)
+ * monotone: Add support for rename, delete, and also diff. (William Uther)
+ * toggle: Fix incompatability between javascript and webkit.
+ * bzr: Add support for rename and delete. (Jelmer Vernooij)
+ * attachment: Use relative paths when inserting links.
+ * toggle: Fix for when html got tidied. Closes: #492529 (Enrico Zini)
+ * cutpaste: New plugin by Enrico Zini
+
+ -- Joey Hess <joeyh@debian.org> Sun, 27 Jul 2008 11:23:13 -0400
+
+ikiwiki (2.54) unstable; urgency=low
+
+ [ Joey Hess ]
+ * Make it possible to load setup files w/o running them. Code
+ needing to do so can call IkiWiki::Setup::load, which will return
+ a hash of values.
+
+ [ Josh Triplett ]
+ * ikiwiki-transition: Fix command-line processing so the prefix_directives
+ transition works again.
+
+ [ Joey Hess ]
+ * template: Add support for a BASENAME variable.
+ * Fixes creation of pages when clicking on WikiLinks starting with "/".
+ * Change deb dependencies to list Text::Markdown before markdown, since
+ the former, while slower, has a much better html parser that avoids
+ numerous bugs.
+ * Move yesno function out of inline and into IkiWiki core, not exported.
+ * 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.
+ * parentlinks: New plugin, split out of ikiwiki core and enabled by default,
+ and several new fields added to allow for advanced styling. (intrigeri)
+ * smileys: Some fixes for escaped smileys.
+ * smileys: Note that smileys need to be double-escaped for the escaping to
+ work. Markdown removes one level of escaping.
+ * Add a postscan hook.
+ * search: Use postscan hook, avoid updating index when previewing.
+ * git: Put web committer name/openid/address in the git author field.
+ The committer's email address is not used (because leaking email addresses
+ is not liked by many users). Closes: #451023
+ * git: Fix parsing of git logs with no commit messages at all.
+ * search: Fixes for title stemming, and use better term for tags.
+ (Gabriel McManus)
+ (Rebuilding the wiki on upgrade to this version is recommended if you
+ use the search plugin.)
+
+ [ 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.
+
+ -- Joey Hess <joeyh@debian.org> Mon, 21 Jul 2008 10:10:52 -0400
+
+ikiwiki (2.53) unstable; urgency=low
* search: generate configuration files once only when rebuilding
(Gabriel McManus)
+ * attachment: Fix an uninitialised value warning when editing a page
+ that currently has no attachments.
+ * Fix a bug with links to pages whose names contained colons.
+ * attachment: Support old versions of CGI.pm that lack an upload method.
+ * Include ikiwiki.setup in examples in the debian package.
+ * attachment: Support perl 5.8's buggy version of CGI.pm.
+ * otl: Support utf-8 files. (Recai Oktaş)
- -- Joey Hess <joeyh@debian.org> Mon, 07 Jul 2008 01:52:48 -0400
+ -- Joey Hess <joeyh@debian.org> Wed, 09 Jul 2008 16:45:33 -0400
ikiwiki (2.52) unstable; urgency=low
pounding on the cgi following edit links.
* passwordauth: If Authen::Passphrase is installed, use it to store
password hashes, crypted with Eksblowfish.
- * `ikiwiki-transiition hashpassword /path/to/srcdir` can be used to
+ * `ikiwiki-transition hashpassword /path/to/srcdir` can be used to
hash existing plaintext passwords.
* Passwords will no longer be mailed, but instead a password reset link.
* The password_cost config setting is provided as a "more security" knob.
Source: ikiwiki
Section: web
Priority: optional
-Build-Depends: perl, debhelper (>= 5)
-Build-Depends-Indep: dpkg-dev (>= 1.9.0), libxml-simple-perl, markdown | libtext-markdown-perl, libtimedate-perl, libhtml-template-perl, libhtml-scrubber-perl, wdg-html-validator, libhtml-parser-perl, liburi-perl
+Build-Depends: perl, debhelper (>= 7.0.50)
+Build-Depends-Indep: dpkg-dev (>= 1.9.0), libxml-simple-perl,
+ libtext-markdown-perl | markdown,
+ libtimedate-perl, libhtml-template-perl,
+ libhtml-scrubber-perl, wdg-html-validator,
+ libhtml-parser-perl, liburi-perl, perlmagick, po4a (>= 0.34)
Maintainer: Joey Hess <joeyh@debian.org>
-Uploaders: Joey Hess <joeyh@debian.org>, Josh Triplett <josh@freedesktop.org>
-Standards-Version: 3.8.0
+Uploaders: Josh Triplett <josh@freedesktop.org>
+Standards-Version: 3.8.1
Homepage: http://ikiwiki.info/
Vcs-Git: git://git.ikiwiki.info/
Vcs-Browser: http://git.ikiwiki.info/?p=ikiwiki
Package: ikiwiki
Architecture: all
-Depends: ${perl:Depends}, markdown | libtext-markdown-perl, libhtml-scrubber-perl, libhtml-template-perl, libhtml-parser-perl, liburi-perl
-Recommends: gcc | c-compiler, libc6-dev | libc-dev, subversion | git-core (>= 1:1.5.0) | tla | bzr (>= 0.91) | mercurial | monotone (>= 0.38), libxml-simple-perl, libnet-openid-consumer-perl, liblwpx-paranoidagent-perl, libtimedate-perl, libcgi-formbuilder-perl (>= 3.05), libcgi-session-perl (>= 4.14-1), libmail-sendmail-perl, libauthen-passphrase-perl
-Suggests: viewvc | gitweb | viewcvs, libsearch-xapian-perl, xapian-omega (>= 1.0.5), librpc-xml-perl, libtext-wikiformat-perl, python, python-docutils, polygen, tidy, libxml-feed-perl, libmailtools-perl, perlmagick, libfile-mimeinfo-perl, libcrypt-ssleay-perl, liblocale-gettext-perl (>= 1.05-1), libtext-typography-perl, libtext-csv-perl, libdigest-sha1-perl, graphviz, libnet-amazon-s3-perl
+Depends: ${misc:Depends}, ${perl:Depends}, ${python:Depends},
+ libtext-markdown-perl | markdown,
+ libhtml-scrubber-perl, libhtml-template-perl,
+ libhtml-parser-perl, liburi-perl
+Recommends: gcc | c-compiler,
+ libc6-dev | libc-dev,
+ subversion | git-core (>= 1:1.5.0) | tla | bzr (>= 0.91) | mercurial | monotone (>= 0.38),
+ libxml-simple-perl, libnet-openid-consumer-perl,
+ liblwpx-paranoidagent-perl, libtimedate-perl,
+ libcgi-formbuilder-perl (>= 3.05), libcgi-session-perl (>= 4.14-1),
+ libmail-sendmail-perl, libauthen-passphrase-perl, libterm-readline-gnu-perl
+Suggests: viewvc | gitweb | viewcvs, libsearch-xapian-perl,
+ xapian-omega (>= 1.0.5), librpc-xml-perl, libtext-wikiformat-perl,
+ python, python-docutils, polygen, tidy, libhtml-tree-perl,
+ libxml-feed-perl, libmailtools-perl, perlmagick,
+ libfile-mimeinfo-perl, libcrypt-ssleay-perl,
+ liblocale-gettext-perl (>= 1.05-1), libtext-typography-perl,
+ libtext-csv-perl, libdigest-sha1-perl, graphviz, libnet-amazon-s3-perl,
+ sparkline-php, texlive, dvipng, libtext-wikicreole-perl,
+ libsort-naturally-perl, libtext-textile-perl, libhighlight-perl,
+ po4a (>= 0.35-1), gettext
Conflicts: ikiwiki-plugin-table
Replaces: ikiwiki-plugin-table
Provides: ikiwiki-plugin-table
The full text of the GPL is distributed as doc/GPL in ikiwiki's source,
and is distributed in /usr/share/common-licenses/GPL-2 on Debian systems.
-Files: templates/*, underlays/basewiki/*, ikiwiki.setup
+Files: templates/*, underlays/basewiki/*, doc/ikiwiki/directive/*, ikiwiki.setup, po/underlay/*
Copyright: © 2006-2008 Joey Hess <joey@ikiwiki.info>
License: other
Redistribution and use in source and compiled forms, with or without
Copyright: © 2006 Emanuele Aina
License: GPL-2+
-Files: monotone.pm
-Copyright: © 2007 William Uther
+Files: monotone.pm, listdirectives.pm, progress.pm
+Copyright: © 2007, 2008 William Uther
License: GPL-2+
Files: tla.pm
Copyright: © 2006 Clint Adams <schizo@debian.org>
License: GPL-2+
+Files: darcs.pm
+Copyright:
+ © 2006 Thomas Schwinge <tschwinge@gnu.org>
+ 2007 Benjamin A'Lee <bma@bmalee.eu>
+ Tuomo Valkonen <tuomov@iki.fi>
+ 2008 Simon Michael <simon@joyful.com>
+ Petr Ročkai <me@mornfall.net>
+ Sven M. Hallberg <pesco@khjk.org>
+License: GPL-2+
+
Files: teximg.pm
Copyright: © 2007 Patrick Winnertz <patrick.winnertz@skolelinux.org>
License: GPL-2+
Copyright: © 2006 Faidon Liambotis
License: GPL-2+
-Files: polygen.pm, pagestats.pm
+Files: htmlbalance.pm, underlay.pm
+Copyright: © 2008 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+License: GPL-2+
+
+Files: polygen.pm, pagestats.pm, cutpaste.pm
Copyright: © 2006 Enrico Zini
License: GPL-2+
Copyright: Copyright (C) 2008 Gabriel McManus <gmcmanus@gmail.com>
License: GPL-2+
+Files: color.pm
+Copyright: Copyright (C) 2008 Paweł Tęcza <ptecza@net.icm.edu.pl>
+License: GPL-2+
+
+Files: google.pm
+Copyright: Copyright (C) 2008 Peter Simons <simons@cryp.to>
+License: GPL-2+
+
+Files: comments.pm
+Copyright:
+ © 2006-2008 Joey Hess <joey@ikiwiki.info>
+ © 2008 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+License: GPL-2+
+
+Files: po.pm
+Copyright: © 2008-2009 intrigeri <intrigeri@boum.org>
+License: GPL-2+
+
+Files: 404.pm
+Copyright: © 2009 Simon McVittie <http://smcv.pseudorandom.co.uk/>
+License: GPL-2+
+
+Files: wmd.pm, getsource.pm
+Copyright: © 2009 William Uther
+License: GPL-2+
+
Files: doc/logo/*
Copyright: © 2006 Recai Oktaş <roktas@debian.org>
License: GPL-2+
--- /dev/null
+ikiwiki.setup
--- /dev/null
+usr/share/ikiwiki/examples usr/share/doc/ikiwiki/examples
+usr/share/common-licenses/GPL-2 usr/share/doc/ikiwiki/html/GPL
# Change this when some incompatible change is made that requires
# rebuilding all wikis.
-firstcompat=2.52
+firstcompat=3.1415926
if [ "$1" = configure ] && \
dpkg --compare-versions "$2" lt "$firstcompat"; then
#!/bin/sh
-
+set -e
#DEBHELPER#
if [ "$1" = upgrade ] && dpkg --compare-versions "$2" lt 1.2; then
fi
fi
fi
+if [ "$1" = upgrade ] && dpkg --compare-versions "$2" lt 3.02; then
+ # replaced by symlink
+ rm -rf /usr/share/doc/ikiwiki/examples
+fi
#!/usr/bin/make -f
+%:
+ dh $@
-build: build-stamp
-build-stamp:
- dh_testdir
- perl Makefile.PL PREFIX=/usr INSTALLDIRS=vendor
- $(MAKE) -C po
- $(MAKE)
- $(MAKE) test
- touch build-stamp
+override_dh_auto_configure:
+ # keeps it out of /usr/local
+ dh_auto_configure -- PREFIX=/usr
-clean:
- dh_testdir
- dh_testroot
- rm -f build-stamp
- perl Makefile.PL
- if [ -e Makefile ]; then $(MAKE) realclean; fi
- dh_clean
-
-binary-arch: build
+override_dh_compress:
+ # avoid compressing files in the doc wiki
+ dh_compress -Xhtml
-binary-indep: build
- dh_testdir
- dh_testroot
- dh_clean -k
- $(MAKE) pure_install DESTDIR=$(shell pwd)/debian/ikiwiki
- dh_install wikilist etc/ikiwiki
- dh_installdocs html
- dh_installexamples doc/examples/*
- dh_link usr/share/common-licenses/GPL-2 usr/share/doc/ikiwiki/html/GPL
- dh_installchangelogs
- dh_compress -X html
- dh_fixperms
- dh_perl
- dh_installdeb
- dh_gencontrol
- dh_md5sums
- dh_builddeb
+override_dh_auto_clean:
+ # distclean moans about MANIFEST, this is quieter
+ if [ -e Makefile ]; then $(MAKE) realclean; fi
# Not intended for use by anyone except the author.
announcedir:
@echo ${HOME}/src/ikiwiki/doc/news
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary
* Rather than inventing yet another simplistic, linear version control system, ikiwiki uses a standard version control system such as [[Subversion|rcs/svn]] or [[rcs/Git]]. You can edit a wiki by committing to your repository, as well as through a traditional web interface. This makes ikiwiki ideal for collaborative software development; just keep your wiki in version control next to your software. You can also take full advantage of the features of these systems; for instance, you can keep a local branch of your wiki via [[rcs/Git]].
-* You can turn any set of pages into a [[ikiwiki/blog]] or similar news feed,
+* You can turn any set of pages into a [[blog]] or similar news feed,
* complete with RSS and Atom support. You can run your weblog on ikiwiki (and [[many_people_do|ikiwikiusers]]), run a Planet-like [[aggregator|plugins/aggregate]] for external feeds, or keep a [[TODO]] and [[bug|bugs]] list with tags for completed items.
* ikiwiki provides a wiki compiler, designed to transform your wiki content into a set of static pages. You can then serve these pages as static content. ikiwiki will not fall over during a Slashdotting, because page views don't require the ikiwiki CGI; as long as your web server can keep up, your site will survive. Furthermore, you can choose whether you want to run the ikiwiki CGI for web edits or only handle commits to the underlying version control system; you can even run ikiwiki privately and just manually copy the content to another server. So if you want to put a wiki up on a server without installing any software on that server, try ikiwiki.
* Bus Nr. 02 - **Wiki Developers Tour** - next stop: [MeatballWiki TourBusStop](http://www.usemod.com/cgi-bin/mb.pl?TourBusStop)
* Bus Nr. 42 - **Software Developers Tour** - next stop: [Ward's Wiki TourBusStop](http://c2.com/cgi/wiki?TourBusStop)
-[[meatballwiki TourBusMap]]
+[[!meatballwiki TourBusMap]]
Famous sights to visit here at **ikiwiki**
==========================================
--- /dev/null
+ikiwiki works with anchors in various situations.
+
+This page accumulates links to the concept of anchors.
-Wiki admins can ban users via their Preferences.
-
-The list of banned users is space delimited.
+Banned users can be configured in the setup file.
If a banned user attempts to use the ikiwiki CGI, they will receive a 403
Forbidden webpage indicating they are banned.
* [[sandbox]]
* [[shortcuts]]
* [[templates]]
-* [[ikiwiki/blog]]
* [[ikiwiki/formatting]]
* [[ikiwiki/markdown]]
* [[ikiwiki/openid]]
* [[ikiwiki/pagespec]]
-* [[ikiwiki/PreprocessorDirective]]
+* [[ikiwiki/directive]]
* [[ikiwiki/subpage]]
* [[ikiwiki/wikilink]]
As well as a few other files, like [[favicon.ico]], [[local.css]],
[[style.css]], and some icons.
+
+Note that an important property of the basewiki is that it should be
+self-contained. That means that the pages listed above cannot link
+to pages outside the basewiki. Ikiwiki's test suite checks that the
+basewiki is self-contained, and from time to time links have to be
+removed (or replaced with `iki` [[shortcuts]]) to keep this invariant.
----
-This wiki is powered by [ikiwiki](http://ikiwiki.info/).
+This wiki is powered by [[ikiwiki]].
--- /dev/null
+Ikiwiki allows turning any page into a weblog, by using the
+[[ikiwiki/directive/inline]] [[ikiwiki/directive]]. For example:
+
+ \[[!inline pages="blog/* and !*/Discussion" show="10" rootpage="blog"]]
Also see the [Debian bugs](http://bugs.debian.org/ikiwiki).
-[[inline pages="bugs/* and !bugs/done and !bugs/discussion and
+[[!inline pages="bugs/* and !bugs/done and !bugs/discussion and
!link(patch) and !link(bugs/done) and !bugs/*/*"
feedpages="created_after(bugs/no_commit_mails_for_new_pages)"
actions=yes rootpage="bugs" postformtext="Add a new bug titled:" show=0]]
--- /dev/null
+The Atom feed from <http://planet.collabora.co.uk/>
+get "double-encoded" (UTF-8 is decoded as Latin-1 and re-encoded as
+UTF-8) when aggregated with IkiWiki on Debian unstable. The RSS 1.0
+and RSS 2.0 feeds from the same Planet are fine. All three files
+are in fact correct UTF-8, but IkiWiki mis-parses the Atom.
+
+This turns out to be a bug in XML::Feed, or (depending on your point
+of view) XML::Feed failing to work around a design flaw in XML::Atom.
+When parsing RSS it returns Unicode strings, but when parsing Atom
+it delegates to XML::Atom's behaviour, which by default is to strip
+the UTF8 flag from strings that it outputs; as a result, they're
+interpreted by IkiWiki as byte sequences corresponding to the UTF-8
+encoding. IkiWiki then treats these as if they were Latin-1 and
+encodes them into UTF-8 for output.
+
+I've filed a bug against XML::Feed on CPAN requesting that it sets
+the right magical variable to change this behaviour. IkiWiki can
+also apply the same workaround (and doing so should be harmless even
+when XML::Feed is fixed); please consider merging my 'atom' branch,
+which does so. --[[smcv]]
+
+[[!tag patch done]]
--- /dev/null
+There is currently a restriction in ikiwiki that there cannot be any symlinks in the source path. This is to deal with a security issue discussed [[here|security#index29h2]]. The issue, as I understand it, is that someone might change a symlink and so cause things on the server to be published when the server admin doesn't want them to be.
+
+I think there are two issues here:
+
+ - Symlinks with the source dir path itself, and
+ - Symlinks inside the source directory.
+
+The first appears to me to be less of a security issue. If there is a way for a malicious person to change where that path points, then you have problems this check isn't going to solve. The second is quite clearly a security issue - if someone were to commit a symlink into the source dir they could cause lots of stuff to be published that shouldn't be.
+
+> Correct. However, where does the revision controlled source directory end? Ikiwiki has no way
+> of knowing. It cannot assume that `srcdir` is in revision control, and
+> everything outside is not. For example, ikiwiki's own source tree has the
+> doc wiki source inside `ikiwiki/doc`. So to fully close the source dir
+> symlink issue, it's best to, by default, assume that the revision
+> controlled directories could go down arbitrarily deep, down to the root of
+> the filesystem. --[[Joey]]
+
+>> Fair point.
+
+The current code seems to check this constraint at the top of IkiWiki/Render.pm at the start of refresh(). It seems to only check the source dir itself, not the subdirs. Then it uses File::Find to recuse which doesn't follow symlinks.
+
+Now my problem: I have a hosted server where I cannot avoid having a symlink in the source path. I've made a patch to optionally turn off the symlink checking in the source path itself. The patch would still not follow symlinks inside the source dir. This would seem to be ok security-wise for me as I know that path is ok and it isn't going to change on me.
+
+> BTW, if you have a problem, please file it in [[todo]] or [[bugs]] in the
+> future. Especially if you also have a patch. :-) --[[Joey]]
+
+>> Well, I was unsure I wasn't missing something. I wanted to discuss the concept of the patch as much as submit the patch. But, ok :)
+
+Is there a huge objection to this patch?
+
+>>> [[patch]] updated.
+
+ diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
+ index 990fcaa..0fb78ba 100644
+ --- a/IkiWiki/Render.pm
+ +++ b/IkiWiki/Render.pm
+ @@ -260,13 +260,15 @@ sub prune ($) {
+
+ sub refresh () {
+ # security check, avoid following symlinks in the srcdir path
+ - my $test=$config{srcdir};
+ - while (length $test) {
+ - if (-l $test) {
+ - error("symlink found in srcdir path ($test)");
+ - }
+ - unless ($test=~s/\/+$//) {
+ - $test=dirname($test);
+ + if (! $config{allow_insecure_symlinks_in_path_to_srcdir}) {
+ + my $test=$config{srcdir};
+ + while (length $test) {
+ + if (-l $test) {
+ + error("symlink found in srcdir path ($test)");
+ + }
+ + unless ($test=~s/\/+$//) {
+ + $test=dirname($test);
+ + }
+ }
+ }
+
+ diff --git a/doc/ikiwiki.setup b/doc/ikiwiki.setup
+ index 10cb3da..eb86e49 100644
+ --- a/doc/ikiwiki.setup
+ +++ b/doc/ikiwiki.setup
+ @@ -203,4 +203,10 @@ use IkiWiki::Setup::Standard {
+ # For use with the attachment plugin, a program that returns
+ # nonzero if its standard input contains an virus.
+ #virus_checker => "clamdscan -",
+ +
+ + # The following setting allows symlinks in the path to your
+ + # srcdir. Symlinks are still not followed within srcdir.
+ + # Allowing symlinks to be followed, even in the path to srcdir,
+ + # will make some setups insecure.
+ + #allow_insecure_symlinks_in_path_to_srcdir => 0,
+ }
+
+> No, I don't have a big objection to such an option, as long as it's
+> extremely well documented that it will make many setups insecure.
+> It would be nice to come up with an option name that makes clear that
+> it's allowing symlinks in the path to the `srcdir`, but still not inside
+> the `srcdir`.
+> --[[Joey]]
+
+>> Slightly modified version of patch applied. --[[Joey]]
+
+>> Ok, I'll try to get it cleaned up and documented.
+
+There is a second location where this can be an issue. That is in the
+front of the wrapper. There the issue is that the path to the source dir
+as seen on the cgi server and on the git server are different - each has
+symlinks in place to support the other. The current wrapper gets the
+absolute path to the source dir, and that breaks things for me. This is a
+slightly different, albeit related, issue to the one above. The following
+patch fixes things. Again, patch inline. Again, this patch could be
+cleaned up :). I just wanted to see if there was any chance of a patch
+like this being accepted before I bothered.
+
+>>> Patch updated:
+
+ index 79b9eb3..ce1c395 100644
+ --- a/IkiWiki/Wrapper.pm
+ +++ b/IkiWiki/Wrapper.pm
+ @@ -4,14 +4,14 @@ package IkiWiki;
+
+ use warnings;
+ use strict;
+ -use Cwd q{abs_path};
+ use Data::Dumper;
+ use IkiWiki;
+ +use File::Spec;
+
+ sub gen_wrapper () {
+ - $config{srcdir}=abs_path($config{srcdir});
+ - $config{destdir}=abs_path($config{destdir});
+ - my $this=abs_path($0);
+ + $config{srcdir}=File::Spec->rel2abs($config{srcdir});
+ + $config{destdir}=File::Spec->rel2abs($config{destdir});
+ + my $this=File::Spec->rel2abs($0);
+ if (! -x $this) {
+ error(sprintf(gettext("%s doesn't seem to be executable"), $this
+ }
+
+> ikiwiki uses absolute paths for `srcdir`, `destdir` and `this` because
+> the wrapper could be run from any location, and if any of them happen to
+> be a relative path, it would crash and burn.
+
+>> Which makes perfect sense. It is annoying that abs_path() is also
+>> expanding symlinks.
+
+> I think the thing to do might be to make it check if `srcdir` and
+> `destdir` look like an absolute path (ie, start with "/"). If so, it can
+> skip running `abs_path` on them.
+
+>> I'll do that. I assume something like <code> File::Spec->file_name_is_absolute( $path ); </code> would have more cross-platformy goodness.
+>> hrm. I might see if <code> File::Spec->rel2abs( $path ) ; </code> will give absolute an path without expanding symlinks.
+>>> Patch using rel2abs() works well - it no longer expands symlinks.
+
+>>>> That patch is applied now. --[[Joey]]
+
+[[!tag done]]
> is already valid utf-8, when in fact it's not yet been decoded. So I
> removed that line to fix it. --[[Joey]]
-[[tag done]]
+[[!tag done]]
--- /dev/null
+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]]
--- /dev/null
+I can't check the last changes in Ikiwiki using
+[gitweb](http://git.ikiwiki.info/?p=ikiwiki). It looks like XML
+validation problem with HTML entity.
+
+When I click a appropriate link on a [[git]] page, then I can only
+see the following error message. --[[Paweł|ptecza]]
+
+ <div class="title"> </div>
+ -------------------^
+
+> I don't see or understand the problem. I've tried History links as well
+> as the diff links in RecentChanges, both seem to be working. --[[Joey]]
+
+>> Hm. It's strange. I really could see the error message like above
+>> when I sent my report. It seems that <http://git.ikiwiki.info/?p=ikiwiki>
+>> URL works now. So, we should be happy that it was self-fixed bug ;)
+>> --[[Paweł|ptecza]]
+
+>>> If it happens again, maybe take a full dump of the page? [[done]]
--- /dev/null
+Error received when clicking on the "edit" link:
+
+> `Error: [CGI::FormBuilder::AUTOLOAD] Fatal: Attempt to address
+> non-existent field 'text' by name at
+> /home/tealart/bin/share/perl/5.8.4/IkiWiki/CGI.pm line 112`
+
+Error received when following a "Create New Page" (eg. ?) link:
+
+> `Error: [CGI::FormBuilder::AUTOLOAD] Fatal: Attempt to address
+> non-existent field 'param' by name at
+> /home/tealart/bin/share/perl/5.8.4/IkiWiki/Plugin/editpage.pm line 122`
+
+I could probably find several other flavors of this error if I went
+looking, but I trust you get the idea.
+
+The CGI starts to render (this isn't the "you forgot to set the
+permissions/turn on the CGI" error) and then fails.
+
+Further details:
+
+- Running on shared hosting (dreamhost; but everything compiles,
+ dependencies installed, the site generates perfectly, other CGIs
+ work, the file permissions work).
+
+- It's running perl 5.8.4, but I did upgrade gettext to 0.17
+
+- the server is running gcc v3.3.5 (at this point, this is the main
+ difference between the working system and my box.)
+
+- I've removed the locale declarations from both the config file and
+ the environment variable.
+
+- I've also modified the page template and have my templates in a non
+ standard location. The wiki compiles fine, with the template, but
+ might this be an issue? The CGI script doesn't (seem) to load under
+ the new template, but I'm not sure how to address this issue.
+
+- All of the required/suggested module dependencies are installed
+ (finally) to the latest version including (relevantly)
+ CGI::FormBuilder 3.0501.
+
+- I'm running ikiwiki v3.08. Did I mention that it works perfectly in
+ nearly every other way that I've managed to test thusfar?
+
+----
+
+> I suspect that your perl is too old and is incompatible with the version of CGI::FormBuilder you have installed.
+>
+> Is so, it seems likely that the same error message can be reproduced by running a simple command like this at the command line:
+>
+> perl -e 'use warnings; use strict; use CGI::FormBuilder; my $form=CGI::FormBuilder->new; $form->text("boo")'
+>
+> --[[Joey]]
+
+> > nope, that command produces no output. :/
+> >
+> > I considered downgrading CGI::FormBuilder but I saw evidence of previous versions being incompatible with ikiwiki so I decided against that.
+> >
+> > -- [[tychoish]]
The "ikwiki.cgi?page=index&do=edit" function has a problem
-when running with [[debpkg thttpd]] or [[debpkg mini-httpd]]:
+when running with [[!debpkg thttpd]] or [[!debpkg mini-httpd]]:
for some reason the headers ikiwiki outputs are transmitted
as the page content. Surprisingly, the "do=prefs" function
works as expected.
<html>
(...)
-Ikiwiki runs fine with [[debpkg boa]].
+Ikiwiki runs fine with [[!debpkg boa]].
--[[JeremieKoenig]]
>>> where ikiwiki might output to stderr, and that's the right thing to do.
>>> So I don't see any way to address this in ikiwiki. --[[Joey]]
->>>> (reported as [[debbug 437927]] and [[debbug 437932]]) --[[JeremieKoenig]]
+>>>> (reported as [[!debbug 437927]] and [[!debbug 437932]]) --[[JeremieKoenig]]
Marking [[done]] since it's not really an ikiwiki bug. --[[Joey]]
+
+----
+
+I'm using boa and getting some odd behaviour if I don't set the `umask`
+option in the config file. Editing a page through the web interface and
+hitting "Save Page" regenerates the `index.html` file with no world-read
+permissions. As a result, the server serves a "403 - Forbidden" error page
+instead of the page I was expecting to return to.
+
+There are only two ways I found to work around this: adding a `umask 022`
+option to the config file, or re-compiling the wiki from the command line
+using `ikiwiki --setup`. Setting up a git back-end and re-running `ikiwiki
+--setup` from inside a hook had no effect; it needed to be at the terminal.
+--Paul
+
+> Since others seem to have gotten ikiwiki working with boa,
+> I'm guessing that this is not a generic problem with boa, but that
+> your boa was started from a shell that had an unusual umask and inherited
+> that. --[[Joey]]
+
+>> That's right; once I'd worked out what was wrong, it was clear that any
+>> webserver should have been refusing to serve the page. I agree about the
+>> inherited umask; I hadn't expected that. Even if it's unusual, though, it
+>> probably won't be uncommon - this was a stock Ubuntu 9.04 install. --Paul
+
+(I'm new to wiki etiquette - would it be more polite to leave these details
+on the wiki, or to remove them and only leave a short summary? Thanks.
+--Paul)
+
+> Well, I just try to keep things understandable and clear, whether than
+> means deleting bad old data or not. That said, this page is a bug report,
+> that was already closed. It's generally better to open a new bug report
+> rather than edit an old closed one. --[[Joey]]
+
+>> Thanks for the feedback, I've tidied up my comment accordingly. I see
+>> your point about the bug; sorry for cluttering the page up. I doubt it's
+>> worth opening a new page at this stage, but will do so if there's a next
+>> time. The solution seems worth leaving, though, in case anyone else in my
+>> situation picks it up. --Paul
> Is it a valid wikilink? Should Iki prevent the page from being created? --[[sabr]], 2 months later
This type of page name (with leading slash) also gets created by the aggregate plugin: /cgi-bin/ikiwiki.cgi?page=%2FCalculated_Risk&from=news%2FAll_Stories&do=create I'm now pretty convinced that Iki should handle this without error. I'll investigate if I can find the time.
+
+> As documented on [[ikiwiki/subpage/linkingrules]], such an absolute
+> link works perfectly when the linked page already exists.
+>
+> The CGI behaviour is thus not consistent with the general linking
+> rules, which is annoying for me : I'm using templates to generate
+> links to pages that may not exist yet, and I would like the "right"
+> path to be selected by default, instead of the usual
+> <current>/subdir/subpage, when a user clicks the "?" link to create
+> the missing page ; that's why I'm using absolute paths.
+>
+>> Totally agree, this had only not been addressed due to lack of time on
+>> my part. (I have about 50 ikiwiki things on my todo list.) --[[Joey]]
+>
+> Anyway, having the CGI consider invalid an otherwise valid wikilink
+> seems a bit weird to me, so I had a look to the code, and here is a
+> patch that should fix this issue ; I proceeded the only way I could
+> find to prevent side-effects : the only place where I use `$origpage`
+> is a match, so no function at all is fed with a `$page` with
+> leading slash :
+>
+> -- intrigeri
+
+
+ diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm
+ index 99cead6..23d9616 100644
+ --- a/IkiWiki/CGI.pm
+ +++ b/IkiWiki/CGI.pm
+ @@ -305,9 +305,11 @@ sub cgi_editpage ($$) {
+ my $page=$form->field('page');
+ $page=possibly_foolish_untaint($page);
+ if (! defined $page || ! length $page ||
+ - file_pruned($page, $config{srcdir}) || $page=~/^\//) {
+ + file_pruned($page, $config{srcdir})) {
+ error("bad page name");
+ }
+ + my $origpage=$page;
+ + $page =~ s#^/##;
+
+ my $baseurl=$config{url}."/".htmlpage($page);
+
+ @@ -425,6 +427,7 @@ sub cgi_editpage ($$) {
+ $from ne $form->field('from') ||
+ file_pruned($from, $config{srcdir}) ||
+ $from=~/^\// ||
+ + $origpage=~/^\// ||
+ $form->submitted eq "Preview") {
+ @page_locs=$best_loc=$page;
+ }
+
+
+> [[Applied|done]]. BTW, I also accept full git changesets, if you like
+> having your name in commit logs. :-)
+
+>> Thanks. I'm considering setting up a public Git repository with topic branches, so that :
+
+>> - I can simply ask you to pull from there, next time
+>> - I have a tool to go on learning the beast (i.e. Git)
+
+>> -- intrigeri
+
+[[!tag patch]]
--- /dev/null
+If I create a page whose title contains an apostrophe, then inlining that
+page produces nothing. It looks like the inline plugin is failing to do
+the translation from apostrophe to `_39_` that other parts of the system do, so although one can make wikilinks to such pages and have them detected as existing (for instance, by the conditional plugin), inline looks in the wrong place and doesn't see the page.
+
+> I can't reproduce that (btw, an apostrophe would be `__39__`) --[[Joey]]
In setting up my wiki I followed the [[setup]] instruction which point
-to an [[ikiwiki.setup]] file that contains "verbose => 0".
+to an ikiwiki.setup file that contains "verbose => 0".
I hadn't noticed that setting in there, but later when I changed my
standard command of:
--- /dev/null
+When a page links to its own #comments anchor you get a link like
+"index.html#comments" rather than "./#comments". Fixed in commit 0844bd0b
+on my 'comments' branch. --[[smcv]]
+
+[[!tag patch done]]
--- /dev/null
+Yes, it's me again :-)
+
+Shouldn't this print a bunch of output (admittedly not very nicely formatted).
+<pre>
+[ 10 rocinante ~/tmp ] ikiwiki --dumpsetup foo.setup
+[ 11 rocinante ~/tmp ] perl -M'IkiWiki::Setup' -e 'print IkiWiki::Setup::load("foo.setup");'
+</pre>
+I get nothing with ikiwiki 2.63 [[DavidBremner]]
+
+> The docs were wrong, it populates `%config`. --[[Joey]] [[done]]
--- /dev/null
+Authen::Passphrase
+
+is entered twice in the .pm file.
+
+[[done]]
--- /dev/null
+I keep getting:
+
+ Error: Your login session has expired.
+
+Whilst trying to edit http://hugh.vm.bytemark.co.uk/ikiwiki.cgi via OpenID. Any ideas?
+
+
+ iki@hugh:~$ dpkg -l | grep openid
+ ii libnet-openid-consumer-perl 0.14-4 library for consumers of OpenID iden
+ tities
+ iki@hugh:~$
+
+> This error occurs if ikiwiki sees something that looks like a CSRF
+> attack. It checks for such an attack by embedding your session id on the
+> page edit form, and comparing that id with the session id used to post
+> the form.
+>
+> So, somehow your session id has changed between opening the edit form and
+> posting it. A few ways this could happen:
+>
+> * Genuine CSRF attack (unlikely)
+> * If you logged out and back in, in another tab, while the edit form was
+> open.
+> * If `.ikiwiki/sessions.db` was deleted/corrupted while you were in the
+> midst of the edit.
+> * If some bug in CGI::Session caused your session not to be saved to the
+> database somehow.
+> * If your browser didn't preserve the session cookie across the edit
+> process, for whatever local reason.
+> * If you were using a modified version of `editpage.tmpl`, and
+> it did not include `FIELD-SID`.
+> * If you upgraded from an old version of ikiwiki, before `FIELD-SID` was
+> added (<= 2.41), and had an edit form open from that old version, and
+> tried to save it using the new.
+>
+> I don't see the problem editing the sandbox there myself, FWIW.
+> (BTW, shouldn't you enable the meta plugin so RecentChanges displays
+> better?)
+> --[[joey]]
+
+
+Thanks for you excellent analysis. The bug was due to old pre-3.0 **templates** laying about. After deleting them, ikiwiki defaults to its own templates. Clever. :-)
+
+[[bugs/done]]
> I take it this is a problem when checking out a wiki in windows, not when
> browsing to urls that have colons in them from windows? --[[Joey]]
->> Correct. You can't directly check out a wiki's repository from Windows if it includes filenames with those characters; you will get errors on those filenames.
\ No newline at end of file
+>> Correct. You can't directly check out a wiki's repository from Windows if it includes filenames with those characters; you will get errors on those filenames.
+
+>>> Ok, first, if a windows user fails to check out ikiwiki's own svn^Wgit
+>>> repo on windows due to the colons, that seems to be a bug in svn^Wgit
+>>> on windows -- those programs should deal with colons in filenames being
+>>> checked in/out somehow. Like they deal with windows using backslash
+>>> rather than slash, presumably. And there's nothing ikiwiki can do if
+>>> the source repo it's working on has a file with a problem character
+>>> added to it, since the breakage will happen at the revision control
+>>> system level.
+
+>>>> Just a quick note that the version control community generally doesn't
+>>>> agree with that view. They'll store what you ask them to store. If you
+>>>> want to work cross platform, then you need to make sure that all
+>>>> your file names work on all the platforms you're interested in. (Note: many systems will
+>>>> warn on commit, but not all. Many systems also have a way to fix
+>>>> the problem without checking out, but not all.) Another common place for this to
+>>>> arise is case insensitive file systems. If you have two files committed
+>>>> that differ only in case, then you cannot check out on a Mac in most systems.
+
+>>> OTOH, there are some simple mods to ikiwiki that can make it escape
+>>> colons etc the same way it already escapes other problem characters
+>>> like "*", "?", etc. Without actually testing it, it should suffice to
+>>> edit `IkiWiki.pm` and modify `titlepage` and `linkpage`, removing the
+>>> colon from the character class in each. Also modify the
+>>> `wiki_file_regexp` similarly. Then ikiwiki will read and
+>>> write files with escaped colons, avoiding the problem.
+>>>
+>>> So that's a simple fix, but on the gripping hand, I can't just make
+>>> that change, because it would break all existing unix-based
+>>> wikis that actually contain colons in their filenames, requiring an
+>>> annoying transition. I could do a OS test and do it in Windows, but then
+>>> there would be interop problems if a Windows and non-windows system both
+>>> acted on the same wiki source.
+
+>>>> I haven't checked the source, but need this break existing wikis?
+>>>> I can imagine a system where a colon gets converted to something safe,
+>>>> and the safe encoding gets converted back to a colon. But if you
+>>>> already have a colon, that doesn't get converted and stays a colon, and
+>>>> so it should still work shouldn't it? The only
+>>>> problem would be with pages that already have the 'safe encoding for a colon'.
+>>>> They'll suddenly change names. Well, I should finish frying my current fish
+>>>> before taking on something new, so I'll shut up now :). -- [[Will]]
+
+>>>>> If `linkpage()` is changed to escape colons, then links to pages
+>>>>> with literal colons in their names will stop working; ikiwiki will
+>>>>> instead look for page names with escaped colons. --[[Joey]]
+
+>>> So, I guess it has to be a config option, possibly defaulting on
+>>> when the OS is Windows. And if being able to checkout/etc the wiki
+>>> source on windows systems is desired, you'd have to remember to turn
+>>> that on when setting up a wiki, even if the wiki was hosted on unix.
+>>>
+>>> Ok, `wiki_file_chars` config option added, set to
+>>> `"-[:alnum:]+/._"` to exclude colons from filenames read or written by
+>>> ikiwiki. [[done]]
+>>>
+>>> BTW, I suspect there are lots of other problems with actually running
+>>> ikiwiki on windows, including its assumption that the directory
+>>> separator is "/". Windows will be supported when someone sends me a
+>>> comprehansive and not ugly or performance impacting patch. :-) --[[Joey]]
+
+> Speaking of Windows filename problems, how do I keep directories ending in a
+> period from being created? The following didn't seem to work.
+> `wiki_file_chars => "-[:alnum:]+/._",`
+> `wiki_file_regex => '[-[:alnum:]+_]$',`
--- /dev/null
+The message generated for web commits:
+
+> web commit by mädduck
+
+is not utf-8 encoded before passed to Git (which uses utf-8 as default encoding for commit messages). This causes a wrongly-encoded log entry, and makes ikiwiki spew warnings as it creates `recentchanges`:
+
+ utf8 "\xF6" does not map to Unicode at /usr/share/perl5/IkiWiki/Rcs/git.pm line 36, <$OUT> line 57.
+ Malformed UTF-8 character (unexpected non-continuation byte 0x6e, immediately after start byte 0xf6) in pattern match (m//) at /usr/share/perl5/IkiWiki/Rcs/git.pm line 393.
+ utf8 "\xF6" does not map to Unicode at /usr/share/perl5/IkiWiki/Rcs/git.pm line 36, <$OUT> line 5.
+
+(This is version 2.53.3~bpo40+1 for lack of a newer backport for sarge)
+
+Please make sure that commit messages for Git are always utf-8.
+
+This is a change by user `mädduck` to trigger the error.
+
+> [[Fixed|done]] both on the commit and log sides. --[[Joey]]
--- /dev/null
+The directive for the graphviz plug-in changed from 'graph' to 'graphviz' in ikiwiki-2.60. Was this intentional?
+
+If yes, the [[plugins/graphviz]] plug-in documentation needs updating, and a heads-up on the news page might not be a bad idea either.
+
+Personally, I like the new directive name better since it will allow us to add other graph plug-ins later.
+
+ -- [[HenrikBrixAndersen]]
+
+> No, that change was not made intentionally. I don't want to bother people
+> with such a transition. Though it would be nice if it had a less generic
+> name. Changed back. [[!tag done]] --[[Joey]]
+++ /dev/null
-The Atom and RSS templates use `ESCAPE=HTML` in the title elements. However, HTML-escaped characters aren't valid according to <http://feedvalidator.org/>.
-
-Removing `ESCAPE=HTML` works fine, but I haven't checked to see if there are any characters it won't work for.
-
-For Atom, at least, I believe adding `type="xhtml"` to the title element will work. I don't think there's an equivalent for RSS.
-
-> Removing the ESCAPE=HTML will not work, feed validator hates that just as
-> much. It wants rss feeds to use a specific style of escaping that happens
-> to work in some large percentage of all rss consumers. (Most of which are
-> broken).
-> <http://www.rssboard.org/rss-profile#data-types-characterdata>
-> There's also no actual spec about how this should work.
->
-> This will be a total beast to fix. The current design is very clean in
-> that all (well, nearly all) xml/html escaping is pushed back to the
-> templates. This allows plugins to substitute fields in the templates
-> without worrying about getting escaping right in the plugins -- and a
-> plugin doesn't even know what kind of template is being filled out when
-> it changes a field's value, so it can't do different types of escaping
-> for different templates.
->
-> The only reasonable approach seems to be extending HTML::Template with an
-> ESCAPE=RSS and using that. Unfortunately its design does not allow doing
-> so without hacking its code in several places. I've contacted its author
-> to see if he'd accept such a patch.
->
-> (A secondary bug is that using meta title currently results in unnecessry
-> escaping of the title value before it reaches the template. This makes
-> the escaping issues show up much more than they need to, since lots more
-> characters are currently being double-escaped in the rss.)
->
-> --[[Joey]]
-
-> Update: Ok, I've fixed this for titles, as a special case, but the
-> underlying problem remains for other fields in rss feeds (such as
-> author), so I'm leaving this bug report open. --[[Joey]]
--- /dev/null
+I'm trying to make a pretty theme for ikiwiki and I'm making progress (or at least I think I am :-). However I've noticed an issue when it comes to theming. On the front page the wiki name is put inside the "title" span and on all the other pages, it's put in the "parentlinks" span. See here:
+
+From [my dev home page](http://adam.shand.net/iki-dev/):
+
+<code>
+<div class="header">
+<span>
+<span class="parentlinks">
+
+</span>
+<span class="title">
+adam.shand.net/iki-dev
+</span>
+</span><!--.header-->
+
+</div>
+</code>
+
+From a sub-page of [my dev home page](http://adam.shand.net/iki-dev/recipes/navajo_fry_bread/):
+
+<code>
+<div class="header">
+<span>
+<span class="parentlinks">
+
+<a href="../">adam.shand.net/iki-dev</a>/
+
+</span>
+<span class="title">
+recipes
+</span>
+</span><!--.header-->
+
+</div>
+</code>
+
+I understand the logic behind doing this (on the front page it is the title as well as the name of the wiki) however if you want to do something different with the title of a page vs. the name of the wiki it makes things pretty tricky.
+
+I'll just modify the templates for my own site but I thought I'd report it as a bug in the hopes that it will be useful to others.
+
+Cheers,
+Adam.
+
+----
+> I just noticed that it's also different on the comments, preferences and edit pages. I'll come up with a diff and see what you guys think. -- Adam.
--- /dev/null
+If a blog entry contains a HTML named entity, such as the `—` produced by [[plugins/rst]] for blockquote citations, it's pasted into the Atom feed as-is. However, Atom feeds don't have a DTD, so named entities beyond `<`, `>`, `"`, `&` and `'` aren't well-formed XML.
+
+Possible solutions:
+
+* Put HTML in Atom feeds as type="html" (and use ESCAPE=HTML) instead
+
+> Are there any particular downsides to doing that ..? --[[Joey]]
+
+>> It's the usual XHTML/HTML distinction. type="html" will always be interpreted as "tag soup", I believe - this may lead to it being rendered differently in some browsers. In general ikiwiki seems to claim to produce XHTML (at least, the default page.tmpl makes it claim to be XHTML Strict). On the other hand, this is a much simpler solution... see escape-feed-html branch in my repository, which I'm now using instead --[[smcv]]
+
+>>> Of course, browsers [probably don't treat xhtml pages as xhtml anyway](http://hixie.ch/advocacy/xhtml).
+>>> And the same content will be treated as html (probably as tag soup) if it's
+>>> in a rss feed.
+
+>>> [[merged|done]]
+
+* Keep HTML in Atom feeds as type="xhtml", but replace named entities with numeric ones,
+ like in the re-escape-entities branch in my repository ([diff here](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=commitdiff;h=c0eb041c65d0653bacf0d4acb7a602e9bda8888e))
+
+>> I can see why you think this is excessively complex! --[[smcv]]
+
+(Also, the HTML in RSS feeds would probably get better interoperability if it was escaped with ESCAPE=HTML rather than being in a CDATA section?)
+
+> Can't see why? --[[Joey]]
+
+>> For a start, `]]>` in content wouldn't break the feed :-) but I was really thinking of non-XML, non-SGML parsers (more tag soup) that don't understand CDATA (I've suffered from CDATA damage when feeding generated code through gtkdoc, for instance). --[[smcv]]
+
+>>> FWIW, the htmlscrubber escapes the `]]>`. (Wouldn't hurt to make that
+>>> more robust tho.)
+>>>
+>>> ikiwiki has used CDATA from the beginning -- this is the first time
+>>> I've heard about rss 2.0 parsers that didn't know about CDATA.
+>>>
+>>> (IIRC, I used CDATA because the result is more space-efficient and less
+>>> craptacular to read manually.)
[[bugs/done]] ; thanks for the patch. Suprised it worked at all since the
bad code was added (did it?) --[[Joey]]
-Thank you for accepting my patch. I can't see how it could ever have worked with the previous code, no. --[[Brix]]
\ No newline at end of file
+Thank you for accepting my patch. I can't see how it could ever have worked
+with the previous code, no. --[[Brix|HenrikBrixAndersen]]
--- /dev/null
+'make test' has the following errors:
+
+Can't locate Locale/gettext.pm in @INC (@INC contains: /home/turian/utils//lib/perl5/site_perl/5.8.8/i386-linux-thread-multi /home/turian/utils//lib/perl5/site_perl/5.8.8 . /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.7/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.6/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.5/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_perl/5.8.7 /usr/lib/perl5/site_perl/5.8.6 /usr/lib/perl5/site_perl/5.8.5 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.7/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.6/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl/5.8.7 /usr/lib/perl5/vendor_perl/5.8.6 /usr/lib/perl5/vendor_perl/5.8.5 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.8/i386-linux-thread-multi /usr/lib/perl5/5.8.8) at (eval 254) line 2.
+
+What's weird is that I already have gettext.pm:
+ /home/turian/utils/lib/perl5/lib/i386-linux-thread-multi/Locale/gettext.pm
+
+That directory should be part of @INC, because I have:
+ export PERL5LIB="$PERL5LIB:$UTILS/lib/perl5/lib/i386-linux-thread-multi/"
+in my .bashrc. However, /home/turian/utils/lib/perl5/lib/i386-linux-thread-multi/ does not appear in that @INC line.
+
+How do I get the proper @INC locations set?
+
+> Nothing in ikiwiki touches whatever PERL5DIR setting you may have,
+> so AFAICS, this must be some sort of local configuration problem.
+> How do
+> `/home/turian/utils//lib/perl5/site_perl/5.8.8/i386-linux-thread-multi`
+> and `/home/turian/utils//lib/perl5/site_perl/5.8.8` get into the
+> displayed `@INC`? The likely way seems to be that something in your
+> system sets PERL5LIB to contain those directories, clobbering
+> the earlier setting in your `.bashrc`.
+> --[[Joey]]
+
+[[!tag done]]
--- /dev/null
+Hmm, according to the docs, shouldn't the following work?
+<pre>
+[ 74 ikipostal/test ] ikiwiki --dumpsetup out.setup foo bar
+[ 75 ikipostal/test ] perl -MIkiWiki::Setup -e'IkiWiki::Setup::load("out.setup");'
+out.setup: Can't use an undefined value as an ARRAY reference at /usr/share/perl5/IkiWiki/Setup.pm line 37.
+BEGIN failed--compilation aborted at (eval 15) line 233.
+</pre>
+
+From looking at the code, it seems that a global hash %config should be
+initialized somehow.
+
+This is in ikiwiki 2.62.1. I think this call used to work in 2.54 (when you first refactored the setup IIRC)
+
+[[DavidBremner]]
+>> Updated:
+>> It seems that `%config = IkiWiki::defaultsetup();IkiWiki::Setup::load("file");`
+>> works (after `use IkiWiki; use IkiWiki::Setup;`). Of course the other api
+>> is nicer.
+
+[[done]], sorry for trouble --[[Joey]]
--- /dev/null
+In IkiWiki/Wrapper.pm, the gen_wrapper function finds out what srcdir and
+destdir are set to in the config, but does not use them.
+
+Later in the sub, when a new wiki.cgi wrapper is being created when calling
+ikiwiki --setup /path/to/setup, it will only work if cgi\_wrapper in the
+config file is set to the full path. Otherwise, it creates wiki.cgi in the
+current working directory. It works with the other wrapper it sets up in
+my config - post\_update (using git), as that shows in the config with a
+full path.
+
+One workaround would be to mention in the setup file that cgi_wrapper has
+to be the full path, not just the file name, but that seems silly when
+destdir is also specified in that file and that's where it should go, and
+$config{destdir} is a known value in the Wrapper.pm file.
+
+> Nowhere in any documentation does
+> it say that cgi\_wrapper is relative to the destdir.
+> As noted in [[discussion]], there are web server setups
+> that require the cgi be located elsewhere.
+> [[done]] --[[Joey]]
+
+>> A comment in the generated setup file that all paths should be full
+>> would prevent my (admittedly dumb) error without any drawbacks.
--- /dev/null
+Just as a point of information, I do not put my cgi wrapper in the dest
+directory. Instead I configure Apache to relate a specific URI to the cgi via
+ScriptAlias. I would not like things to be changed so that the cgi was put in
+the destdir, so I'd vote instead to comment in the `setup\_file`. -- [[Jon]]
--- /dev/null
+ikiwiki has files that are not group-readable:
+
+ -rw------- 1 joseph users 541 Aug 18 12:02 index.atom
+ -rw------- 1 joseph users 2328 Aug 18 12:02 index.html
+ -rw------- 1 joseph users 282 Aug 18 12:02 index.rss
+
+I chmod a+r them, but then when I edit something through the web, its permissions are reverted to only user-readable. How do I resolve this?
+
+ -- [[JosephTurian]]
+
+> My index files have the correct permissions. Have you tried setting 'umask => 022' in your ikiwiki.setup file?
+> -- [[HenrikBrixAndersen]]
+
+> > Thanks Henrik, that worked. Bug is [[bugs/done]]. -- [[JosephTurian]]
--- /dev/null
+It seems that the [[ikiwiki/directive/inline]] directive doesn't generate wikilinks to the pages it includes. For example I would expect the following to inline all bugs inside this bug report:
+
+\[[!inline pages="bugs/* and !*/discussion and backlink(bugs)" feeds=no postform=no archive=yes show="10"]]
+
+But here it is:
+
+[[!inline pages="bugs/* and !*/discussion and backlink(bugs)" feeds=no postform=no archive=yes show="10"]]
+
+and note that it only included the 'normal' wikilinks (and also note that this page is not marked done even though the done page is inlined).
+One might also wonder if inline would make this page link to any internal links on those inlined pages too, but I think
+that would be overkill.
+
+I'm not even really sure if this is a bug or defined behaviour, but I thought it might work and it didn't. Regardless,
+the correct behaviour, whichever is decided, should be documented. -- [[Will]]
+
+It appears that [[ikiwiki/directive/map]] also doesn't wikilink to the pages it links. Perhaps in each of these
+cases there should be another parameter to the directive that allows linking to switched on. Just switching
+it on universally at this point might break a number of people's pagespecs. -- [[Will]]
+
+> There's a simple reason why these directives don't generate a record of a
+> wikilink between them and the pages they include: Semantically, inlining
+> a page is not the same as writing a link to it. Nor is generating a map that
+> lists a page the same as linking to it. I don't think this is a bug.
+> --[[Joey]]
+
+>> Fair enough. I guess we can mark this as [[done]] then.
+>>
+>> Just a bit of background on where I was going here... I was looking for
+>> a simpler way of attacking [[todo/tracking_bugs_with_dependencies]].
+>> In particular, rather than introducing changes to the pagespec definition,
+>> I wondered if you could use wiki pages as the defined pagespec and
+>> introduce a 'match_mutual' function which matches whenever two pages
+>> link to the same third page, then you don't need to alter the pagespec
+>> handling code.
+>>
+>> But that requires being able use use a pagespec to decide what pages
+>> are linked to. e.g. I want to make an 'openbugs' page that links to all
+>> open bugs. Then I could make a 'readybugs' page that links to
+>> `backlink(openbugs) and !mutualLink(openbugs)`. That is, all bugs
+>> that are open and do not themselves link to an open bug.
+>>
+>> The problem with all this is that it introduces an ordering dependency,
+>> as I noted below. I think the original proposal is better, because it
+>> handles that ordering dependency in the definition of the pagespecs.
+>> --[[Will]]
+
+Here is a patch to make map link to its linked pages (when passed `link="yes"`). It is a bit problematic in that it uses a pagespec
+to decide what to link to (which is why I wanted it). However, at the time the pagespec is used the links
+for each page haven't finished being calculated (we're using the pagespec to figure out those links,
+remember). This means that some pagespec match functions may not work correctly. Sigh.
+It would be nice to find a topological ordering of the pages and scan them in that order
+so that everything we need is found before we need it, but this patch doesn't do that (it would be
+complex).
+
+If you just use simple pagespecs you'll be fine. Unfortunately I really wanted this for more complex
+pagespecs. -- [[Will]]
+
+ diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm
+ index 3284931..57c0a7a 100644
+ --- a/IkiWiki/Plugin/map.pm
+ +++ b/IkiWiki/Plugin/map.pm
+ @@ -13,7 +13,7 @@ use IkiWiki 3.00;
+
+ sub import {
+ hook(type => "getsetup", id => "map", call => \&getsetup);
+ - hook(type => "preprocess", id => "map", call => \&preprocess);
+ + hook(type => "preprocess", id => "map", call => \&preprocess, scan => 1);
+ }
+
+ sub getsetup () {
+ @@ -27,7 +27,9 @@ sub getsetup () {
+ sub preprocess (@) {
+ my %params=@_;
+ $params{pages}="*" unless defined $params{pages};
+ -
+ +
+ + return if (!defined wantarray && !IkiWiki::yesno($params{link}));
+ +
+ my $common_prefix;
+
+ # Get all the items to map.
+ @@ -42,6 +44,9 @@ sub preprocess (@) {
+ else {
+ $mapitems{$page}='';
+ }
+ + if (!defined wantarray && IkiWiki::yesno($params{link})) {
+ + push @{$links{$params{page}}}, $page;
+ + }
+ # Check for a common prefix.
+ if (! defined $common_prefix) {
+ $common_prefix=$page;
+ @@ -62,6 +67,8 @@ sub preprocess (@) {
+ }
+ }
+
+ + return if ! defined wantarray;
+ +
+ # Common prefix should not be a page in the map.
+ while (defined $common_prefix && length $common_prefix &&
+ exists $mapitems{$common_prefix}) {
+ }
+
+ return eval $newpagespec;
- } #}}}
+ }
package IkiWiki::PageSpec;
+ my $ret=eval possibly_foolish_untaint(pagespec_translate($spec));
return IkiWiki::FailReason->new("syntax error") if $@;
return $ret;
- } #}}}
+ }
>> Thanks a lot, Joey! It works :)
>>
>>> Ubuntu Gutsy also has Perl 5.8.8-7, so probably it has the bug too.
>>> --[[Paweł|ptecza]]
+
+>>>> I just got it while building my latest version of git.ikiwiki.info + my stuff.
+>>>> Only thing different in my version in IkiWiki.pm is that I moved a </a> over
+>>>> a word (for createlink), and disabled the lowercasing of created pages. Running
+>>>> Lenny's Perl. --[[simonraven]]
+
+>>>> Simon, I'm not clear what version of ikiwiki you're using.
+>>>> Since version 2.40, taint checking has been disabled by
+>>>> default due to the underlying perl bug. Unless you
+>>>> build ikiwiki with NOTAINT=0. --[[Joey]]
+
+>>>> Hi, nope not doing this. Um, sorry, v. 3.13. I've no idea why it suddenly started doing this.
+>>>> It wasn't before. I've been messing around IkiWiki.pm to see if I can set
+>>>> a umask for `mkdir`.
+
+line 775 and down:
++ umask ($config{umask} || 0022);
+
+>>>> I figured it *might* be the `umask`, but I'll see in a few when / if it gets past that in the build. No; I keep getting garbage during the brokenlinks test
+
+<pre>
+t/basewiki_brokenlinks.....Insecure dependency in mkdir while running with -T switch at IkiWiki.pm line 776.
+
+# Failed test at t/basewiki_brokenlinks.t line 11.
+
+# Failed test at t/basewiki_brokenlinks.t line 19.
+
+
+broken links found
+<li>shortcut from <a href="./shortcuts/">shortcuts</a></li></ul>
+
+
+
+# Failed test at t/basewiki_brokenlinks.t line 25.
+Insecure dependency in mkdir while running with -T switch at IkiWiki.pm line 776.
+
+# Failed test at t/basewiki_brokenlinks.t line 11.
+
+# Failed test at t/basewiki_brokenlinks.t line 25.
+# Looks like you failed 5 tests of 12.
+dubious
+ Test returned status 5 (wstat 1280, 0x500)
+</pre>
+
+>>>> I get this over and over... I haven't touched that AFAICT, at all. --[[simonraven]]
+
+>>>>> Take a look at your `/usr/bin/ikiwiki`. The first
+>>>>> line should not contain -T. If it does, remove it,
+>>>>> and maybe try to work out or give details about how
+>>>>> you installed ikiwiki and why it got the -T in there,
+>>>>> which certianly doesn't happen by default when ikiwiki
+>>>>> is installed by the Makefile.PL or by any package I know of.
+>>>>> (If there's
+>>>>> no -T, then something *really* weird is going on..)
+>>>>> --[[Joey]]
+
+>>>>>> nope, no -T in the hashbang line at all. Haven't added any;
+>>>>>> only thing I did there was change `use lib` to `/usr/share/perl5`,
+>>>>>> otherwise I'd get bogus errors about CGI::Cookie_al or some such thing.
+>>>>>>
+>>>>>> How I installed it was in non-public directories in various sites, then
+>>>>>> make it publish stuff to a public dir in the relevant site. Or do you
+>>>>>> mean installed, as in the whole thing? From a .deb I made based on the git tree, with `git-buildpackage`.
+>>>>>>
+>>>>>> This issue is recent, after a `git pull` IIRC. It has never happened before. It's also puzzling me.
+>>>>>>
+>>>>>> You can check it out for yourself by pulling my fork of this, at github or my local repo.
+>>>>>> github will probably be faster for you: git://github.com/kjikaqawej/ikiwiki-simon.git --[[simonraven]]
+
+>>>>>>> I don't know what I'm supposed to see in your github tree.. it
+>>>>>>> looks identical to an old snapshot of ikiwiki's regular git repo?
+>>>>>>> If you want to put up the .deb you're using, I could examine that.
+>>>>>>>
+>>>>>>> I was in fact able to reproduce the insecure dependency in mkdir
+>>>>>>> message -- but only if I run 'perl -T ikiwiki'.
+>>>>>>> --[[Joey]]
> apparently all versions of perl, apparently leaking taint flags at random.
> See [[Insecure_dependency_in_mkdir]] --[[Joey]]
-[[tag done]]
+[[!tag done]]
--- /dev/null
+We just installed 2.52 on debian testing, and all edit links with symbols (including spaces) are coming up with empty text fields because the URL to the mdwn file is wrong.
+
+For example, the existing page:
+
+ wiki/bugs/__39__Existing_Subject__39___vs.___39__Browse__39__/
+
+displays the bug "'Existing Subject' vs. 'Browse'". But if we click 'Edit' on that page, we get:
+
+ wiki/ikiwiki.cgi?page=bugs%2F'Existing%20Subject'%20vs.%20'Browse'&do=edit
+
+.. which of course opens with a blank edit box. Note that manually typing in the correct URL:
+
+ wiki/ikiwiki.cgi?page=bugs%2F__39__Existing_Subject__39___vs.___39__Browse__39__&do=edit
+
+does work.
+
+> You need to rebuild your wiki on upgrade to 2.52. The *old* edit links
+> looked like the first link above, and ikiwiki has changed so that it
+> needs the new link above. To get those links on static pages, you need to
+> rebuild the wiki, like the [[news]] says to.
+>
+> [[closing|done]] as user error --[[Joey]]
--- /dev/null
+My <code>page.tmpl</code> can contain:
+
+ Created <TMPL_VAR CTIME>. Last edited <TMPL_VAR MTIME>.
+
+and that works. However, if I have the same line in <code>inlinepage.tmpl</code>
+or <code>archivepage.tmpl</code>, then only the <code>CTIME</code> works - the <code>MTIME</code> is blank.
+This leads to an annoying inconsistency.
+
+Update - even though I'm not a Perl programmer, this patch seems right:
+
+ --- /home/bothner/ikiwiki/ikiwiki/IkiWiki/Plugin/inline.pm 2008-10-01 14:29:11.000000000 -0700
+ +++ ./inline.pm 2008-10-12 13:26:11.000000000 -0700
+ @@ -316,6 +316,7 @@
+ $template->param(pageurl => urlto(bestlink($params{page}, $page), $params{destpage}));
+ $template->param(title => pagetitle(basename($page)));
+ $template->param(ctime => displaytime($pagectime{$page}, $params{timeformat}));
+ + $template->param(mtime => displaytime($pagemtime{$page}, $params{timeformat}));
+ $template->param(first => 1) if $page eq $list[0];
+ $template->param(last => 1) if $page eq $list[$#list];
+
+
+> [[done]], thanks
In `wiki-wc/factors/tag.mdwn`, I have a map for these tags:
- \[[map pages="factors/tag/*"]]
+ \[[!map pages="factors/tag/*"]]
and this works, except that for *whatever* reason, it actually sorts the three
`affects/*` tags under `active`:
--- /dev/null
+I have been trying to include some meta info using the link setting something like the below
+
+ meta link="http://www.example.com/" rel="command" name="Example"
+
+This gets removed by the htmlscrubber as you would expect.
+
+Setting htmlscrubber_skip to the pagespec should stop this getting scrubbed but it does not.
+
+Below is a patch to fix that. It seams to work but I am not sure of it is the correct thing to do.
+
+> [[done]], thanks for the patch --[[Joey]]
--- /dev/null
+Trying to build current Git master in a (two weeks old - no DSL here) sid chroot triggers :
+
+ rendering news.mdwn
+ Can't locate Image/Magick.pm in @INC (@INC contains: . blib/lib /etc/perl /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .) at (eval 175) line 2.
+ BEGIN failed--compilation aborted at (eval 175) line 2.
+
+ make[1]: *** [extra_build] Error 2
+ make[1]: Leaving directory `/tmp/buildd/ikiwiki-2.54'
+ make: *** [build-stamp] Error 2
+
+Adding perlmagick to the build-deps fixes it. I read somewhere in debian/changelog that this build-deb was not needed, but...
+
+> It's not needed by the test suite, but once I added a img to the source
+> wiki, it became needed. [[done]] --[[Joey]]
Here for future reference is the most recent version of support for
that I've been sent. It's not yet working; there are path issues. --[[Joey]]
-> I think this was fixed in version 2.40. --[[Joey]] [[tag done]]
+> I think this was fixed in version 2.40. --[[Joey]] [[!tag done]]
<pre>
diff --git a/IkiWiki/Rcs/monotone.pm b/IkiWiki/Rcs/monotone.pm
index cde6029..34f8f96 100644
--- a/IkiWiki/Rcs/monotone.pm
+++ b/IkiWiki/Rcs/monotone.pm
-@@ -186,8 +186,9 @@ sub rcs_update () { #{{{
+@@ -186,8 +186,9 @@ sub rcs_update () {
check_config();
if (defined($config{mtnsync}) && $config{mtnsync}) {
</TMPL_IF>
> Well, that don't look like as good an idea today.. I've documented the
-> recent template change. --[[Joey]] [[tag done]]
+> recent template change. --[[Joey]] [[!tag done]]
enabled, then `$safe_url_regexp` determines the URL unsafe because of the
colon and hence removes the `src` attribute.
-Digging into this, I find that [[rfc 3986]] pretty much discourages colons in
+Digging into this, I find that [[!rfc 3986]] pretty much discourages colons in
filenames:
> A path segment that contains a colon character (e.g., "this:that") cannot be
[Commit/patch
be0b4f60](http://git.madduck.net/v/code/ikiwiki.git?a=commit;h=be0b4f603f918444b906e42825908ddac78b7073) fixes this.
-[[done]]
+
+**July 21 2008:** I update this bug report as it still seems to be an issue: E.g. when creating a subpage whose name contains
+a colon by inserting an appropriate wikilink in the parent page: the new page can be created using that link, but afterwards
+there won't be a link to this page. Like madduck said above it seems to be htmlscrubber removing this link. However everything
+works fine if the same page is being linked to from another subpage because in that case the resulting link starts with `../`.
+
+At the moment I see two possible solutions:
+
+1. let all relative links at least start with `./`. I haven't tested this.
+
+2. Escape the colon in page titles. I created the following patch which worked for me:
+
+ --- IkiWiki.pm.2.53-save 2008-07-08 15:56:38.000000000 +0200
+ +++ IkiWiki.pm 2008-07-21 20:41:35.000000000 +0200
+ @@ -477,13 +477,13 @@
+
+ sub titlepage ($) {
+ my $title=shift;
+ - $title=~s/([^-[:alnum:]:+\/.])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
+ + $title=~s/([^-[:alnum:]+\/.])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
+ return $title;
+ }
+
+ sub linkpage ($) {
+ my $link=shift;
+ - $link=~s/([^-[:alnum:]:+\/._])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
+ + $link=~s/([^-[:alnum:]+\/._])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg;
+ return $link;
+ }
+
+What do you think about that? Does the patch have any side-effects I didn't see?
+
+> I almost really fixed this in 2.53, but missed one case. All fixed now
+> AFAICS. --[[Joey]]
+
+>> Hmm, did you fix it now in 2.54? If so, I suspect there is still one little case left (might well be the last one,
+>> at least I hope so ;-) ): I just created a test post in the sandbox here: [[sandbox/test: with a colon in its name]]
+>> (btw, why doesn't this get a hyperlink here?).
+>>
+>>> Because wikilinks cannot have spaces, convert to underscores.
+>>> --[[Joey]]
+>>
+>> As it is put in the list of blog posts as a relative link, it starts
+>> with `<word><colon>` -- this makes the browser think that "test" is a protocol specification which is to replace `http`,
+>> so it complains (at least Opera and Firefox/Iceweasel on my Debian Etch do). What I described above for subpages
+>> with this name pattern also still happens on my local install (ikiwiki 2.54 on Debian Etch), but this is basically
+>> the same problem.
+>>
+>> I think the cleanest solution would be to quote colons in page names (like it is currently done for slashes)?
+>> Starting the links with "`./`", as I proposed above, now seems a bit ugly to me... --Mathias
+
+>>> No, it's all [[done]] in 2.55. --[[Joey]]
--- /dev/null
+I've just upgraded my Ikiwiki to backported version 2.64 for Ubuntu Hardy
+and wanted to see progress bar in action. Unfortunately, I can't see any progress.
+
+This is my example Ikiwiki syntax:
+
+ [[!progress percent=75]]
+
+A here is a HTML result:
+
+ <div class="progress">
+ <div class="progress-done"></div>
+ </div>
+
+It seems that progress plugin works at all, but it's a problem with passing
+progress value.
+
+Anyone can confirm the bug? --[[Paweł|ptecza]]
+
+> You are correct. The above example does generate the HTML you suggest. The
+> plugin requires a % sign:
+
+[[!progress percent="75%"]]
+
+> This could probably be improved. Certainly the documentation could be. -- [[Will]]
+
+>> Thanks for the hint, Will! I could check better the code... However, in my opinion
+>> that '%' sign is confusing here and should be dropped. I hope it's clear for all
+>> people that "percent" parameter passes values in percentages. --[[Paweł|ptecza]]
+
+>>> [[fixed|done]] --[[Joey]]
+
+>>> I've forgotten to add that now the HTML code is OK, but I can see only
+>>> "75%" string on white background wihout any border. I need to look closer
+>>> at CSS styles for the progress bar. --[[Paweł|ptecza]]
+
+>>>> You need the `div.progress` and `div.progress-done` from ikiwiki's
+>>>> default `style.css`. --[[Joey]]
+
+>>>>> Thank you for the fix, Joey!
+
+>>>>> I had `div.progress*` in the `style.css` file, but my Epiphany didn't want
+>>>>> to display the progress bar... Now it's OK and I can see beautiful progress,
+>>>>> though I've not changed anything. --[[Paweł|ptecza]]
--- /dev/null
+The templates/estseek.conf file can safely be removed now that ikiwiki has switched to using xapian-omega.
+
+> Thanks for the reminder, [[done]] --[[Joey]]
--- /dev/null
+When I use my OpenID, http://thewordnerd.info, I am redirected to
+http://thewordnerd.myopenid.com, the identity to which thewordnerd.info
+delegates. That is, I'm redirected to the exact identity URL, not to an
+authorization link.
+
+I am successfully using thewordnerd.info as my identity on many sites, so I
+know the delegation is pretty standard. It's stock WordPress with the
+delegation plugin. I also just attempted registration on http://identi.ca
+and successfully exchanged sreg data. So it seems like something is broken
+when using a delegate specifically with ikiwiki, and while I can use
+thewordnerd.myopenid.com, I'd rather use my delegate and free myself to
+switch to other providers in the future.
+
+> Hmm, I entered http://thewordnerd.info as the openid, and ended up at
+> http://thewordnerd.myopenid.com/ , which seems right? --[[Joey]]
+
+Sorry, didn't notice this edit. But, no, that is incorrect. Entering http://thewordnerd.info or thewordnerd.info should do the exact same thing that entering http://thewordnerd.myopenid.com does--in your case, prompt you to log in, in mine, ask if I want to verify the request. It's redirecting to the page itself, not using it as an OpenID provider.
+
+Unfortunately I don't speak or understand enough Perl to fix this, nor do I understand how to use its debugger, but it looks as if the consumer should support delegation. Not sure why it's behaving incorrectly here.
+
+> Your openid delegation is wrong.
+>
+> Here is a working openid delegation (from http://joey.kitenet.net:)
+> <link href="http://www.myopenid.com/server" rel="openid.server" />
+> <link href="http://www.myopenid.com/server" rel="openid2.provider" />
+> <link href="https://joeyh.myopenid.com/" rel="openid.delegate" />
+> <link href="https://joeyh.myopenid.com/" rel="openid2.local_id" />
+>
+> The above is generated by ikiwiki, using the meta openid directive:
+>
+> \[[meta openid="https://joeyh.myopenid.com/" server="http://www.myopenid.com/server"]]
+>
+> Here is your delegation:
+>
+> <meta http-equiv="X-XRDS-Location" content="http://thewordnerd.myopenid.com/xrds" />
+> <link rel="openid.server" href="http://thewordnerd.myopenid.com" />
+> <link rel="openid.delegate" href="http://thewordnerd.myopenid.com" />
+>
+> So, your openid.server is set wrong; when loging in ikiwiki redirects to
+> the specified url, which is not behaving as an openid server at all. If it's changed
+> to use http://www.myopenid.com/server, it would work the same as mine.
+>
+> I suspect that it was working for you on other sites that support openid
+> 2.0 and XRDS, since the xrds file on your site seems to have the correct
+> http://www.myopenid.com/server url in it. Ikiwiki, however, uses perl
+> modules that do not support openid 2.0 or XRDS, and so the incorrect
+> openid 1.0 delegation is used. --[[Joey]]
+
+[[done]]
+
+Seems so, thanks.
+
+For future reference, and in case anyone has a similar problem and searches here first as I did, I set my OpenID settings using the examples shown for the WordPress OpenID delegation plugin, which seem to work fine on a whole bunch of other sites but a) not here and b) are inaccurate according to the MyOpenID FAQ. I'll file a bug against that plugin to either update its example or remove it entirely. So not an ikiwiki bug, but someone's bug nonetheless.
--- /dev/null
+If a PNG image matches the [[ikiwiki/PageSpec]] of an [[ikiwiki/directive/inline]] directive, the page throws the following error:
+
+> \[[!inline Error: Malformed UTF-8 character (fatal) at /usr/local/lib/perl5/site_perl/5.8.8/File/MimeInfo.pm line 120.]]
+
+Individual posts display fine, and moving the offending image outside the scope of the [[ikiwiki/directive/inline]] directive's PageSpec eliminates the error.
+
+> I tried to reproduce this with a random png and File::MimeInfo
+> version 0.15, but could not. The png was included in the generated feed
+> via an enclosure, as it should be; no warnings or errors.
+>
+> Looking at the source to File::MimeInfo and its changelog,
+> I'm pretty sure that this problem was fixed in version
+> 0.14:
+>> - Fixed bug with malformed utf8 chars in default() method
+>
+> The code involved in that fix looks like this:
+>
+>> no warnings; # warnings can be thrown when input not ascii
+>> if ($] < 5.008 or ! utf8::valid($line)) {
+>> use bytes; # avoid invalid utf8 chars
+>
+> I guess that your locally installed version of File::MimeInfo is older than
+> this. So closing this bug [[done]]. If you still see the problem with a current
+> version of File::MimeInfo, please reopen and include where I can get a png file
+> that triggers the problem. --[[Joey]]
--- /dev/null
+In ikiwiki-2.60, external plug-ins are yet again installed using 'cp -a' instead of 'install -m 755'. This poses a problem on at least FreeBSD 6.x, since the cp(1) command doesn't support the '-a' flag.
+
+The change in question (from 2.56 to 2.60) can be seen here:
+
+ - for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\*`; do \
+ - install -m 755 $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ - done; \
+ + for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\* | grep -v demo`; do \
+ + cp -a $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ + done \
+
+Please restore the old behaviour of using 'install' :-)
+
+ -- [[HenrikBrixAndersen]]
+
+> I use cp -a because I don't want non-executable files to be installed
+> executable. (Causes breakage with setup file creation code) I really
+> wish *BSD could get out of the 70's in this area..
+> --[[Joey]]
+
+>> Well, really what's happening here is that *BSD (along with, for
+>> example, Solaris) is adhering rather closely to the Single UNIX
+>> Specification, whereas `-a` is a nonstandard option added to the
+>> GNU variant of `cp` (a habit Richard Stallman never really got under
+>> control). To install ikiwiki on Solaris I had to replace all uses not
+>> only of `cp` but also of `install` and `xgettext` with the GNU
+>> embrace-and-extend variants, and make sure I had those installed.
+>> That really is a bit of a PITA.
+
+>> I think there's an opportunity here for a really clean solution, though.
+
+>> Why not do the installation in pure Perl?
+
+>> The file manipulations being done by `cp` and `install` would be
+>> straightforward to code in Perl, and there really isn't a complicated
+>> build requiring the full functionality of `gmake`. `gxgettext` I'm
+>> not so sure about, but even getting rid of _almost_ all the
+>> nonstandard-utility dependencies would be a win.
+
+>> The idea is that if you're distributing a Perl-based app, one thing
+>> you'll always be absolutely certain of in the target environment is a
+>> working Perl. The fact that the current build starts out in Perl, but
+>> uses it to write a Makefile and then hand off to other utilities that
+>> are less dependably compatible across platforms is a disadvantage.
+
+>> A pure-Perl install can also query the very Perl it's running in to
+>> determine the proper places to install files, and that will be less
+>> error-prone that making a human edit the right paths into some files.
+>> It would be quite useful here, actually, where we have several distinct
+>> Perl builds installed at different paths, and ikiwiki could be correctly
+>> installed for any one of them simply by using the chosen Perl to run the
+>> install. That means this would also be a complete solution to
+>> [[todo/assumes_system_perl|todo/assumes_system_perl]].
+>> --ChapmanFlack
+
+>>> Joey: How about the following patch, then? -- [[HenrikBrixAndersen]]
+
+ --- Makefile.PL.orig 2008-08-16 14:57:00.000000000 +0200
+ +++ Makefile.PL 2008-08-16 15:03:45.000000000 +0200
+ @@ -67,9 +67,12 @@ extra_install:
+ done
+
+ install -d $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins
+ - for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\* | grep -v demo`; do \
+ - cp -a $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ - done \
+ + for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\* ! -name \*demo\* -name \*.py`; do \
+ + install -m 644 $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ + done
+ + for file in `find plugins -maxdepth 1 -type f ! -wholename plugins/.\* ! -name \*demo\* ! -name \*.py`; do \
+ + install -m 755 $$file $(DESTDIR)$(PREFIX)/lib/ikiwiki/plugins; \
+ + done
+
+ install -d $(DESTDIR)$(PREFIX)/share/man/man1
+ install -m 644 ikiwiki.man $(DESTDIR)$(PREFIX)/share/man/man1/ikiwiki.1
+
+[[!tag done]]
> Thanks for the patch, but I already fixed this in 2.4 using a different
> approach. I think your patch is slightly broken, an anchor tag isn't
> really meant to enclose all the html it anchors to, but just be stuck in
-> front of it. --[[Joey]] [[tag done]]
+> front of it. --[[Joey]] [[!tag done]]
--- IkiWiki/Plugin/toc.pm.orig Thu Jun 7 11:53:53 2007
+++ IkiWiki/Plugin/toc.pm Thu Jun 7 13:00:00 2007
- @@ -47,7 +47,7 @@ sub format (@) { #{{{
+ @@ -47,7 +47,7 @@ sub format (@) {
if ($tagname =~ /^h(\d+)$/i) {
my $level=$1;
my $anchor="index".++$anchors{$level}."h$level";
# Take the first header level seen as the topmost level,
# even if there are higher levels seen later on.
- @@ -90,6 +90,16 @@ sub format (@) { #{{{
+ @@ -90,6 +90,16 @@ sub format (@) {
"</a>\n";
$p->handler(text => undef);
}, "dtext");
--- IkiWiki/Plugin/graphviz.pm.orig 2007-07-27 11:35:05.000000000 +0200
+++ IkiWiki/Plugin/graphviz.pm 2007-07-27 11:36:02.000000000 +0200
- @@ -69,7 +69,12 @@ sub render_graph (\%) { #{{{
+ @@ -69,7 +69,12 @@ sub render_graph (\%) {
}
}
+ else {
+ return "<img src=\"".urlto($dest, $params{page})."\" />\n";
+ }
- } #}}}
+ }
- sub graph (@) { #{{{
+ sub graph (@) {
>> --[[HenrikBrixAndersen]]
--- graphviz.pm.orig Thu Jun 7 15:45:16 2007
+++ graphviz.pm Fri Jun 8 12:03:38 2007
- @@ -41,7 +41,6 @@ sub render_graph (\%) { #{{{
+ @@ -41,7 +41,6 @@ sub render_graph (\%) {
$pid=open2(*IN, *OUT, "$params{prog} -Tpng");
# open2 doesn't respect "use open ':utf8'"
binmode (OUT, ':utf8');
print OUT $src;
- @@ -70,7 +69,12 @@ sub render_graph (\%) { #{{{
+ @@ -70,7 +69,12 @@ sub render_graph (\%) {
}
}
+ else {
+ return "<img src=\"".urlto($dest, $params{page})."\" />\n";
+ }
- } #}}}
+ }
- sub graph (@) { #{{{
+ sub graph (@) {
diff -upr ikiwiki-1.49.orig/IkiWiki/Rcs/svn.pm ikiwiki-1.49/IkiWiki/Rcs/svn.pm
--- ikiwiki-1.49.orig/IkiWiki/Rcs/svn.pm Mon Apr 16 15:15:09 2007
+++ ikiwiki-1.49/IkiWiki/Rcs/svn.pm Mon Apr 16 15:15:47 2007
- @@ -176,7 +176,6 @@ sub rcs_recentchanges ($) { #{{{
+ @@ -176,7 +176,6 @@ sub rcs_recentchanges ($) {
}
foreach (keys %{$logentry->{paths}}) {
> This bug is [[done]], all issues are fixed. --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
--- /dev/null
+[[RecentChanges]] should not link to pages that are being deleted. For as
+example, see the change with the title 'add news item for ikiwiki 2.60'
+which includes the deletion of "news/version 2.52". Maybe it should be made
+clear in RecentChanges that the change to the file is it being deleted.
+
+> It needs to link to the deleted page so that you can recreate the page if
+> desired.
+>
+> The link is not of the normal form used for a link to a nonexistant page,
+> instead it redirects through a CGI. This is done because updating the
+> links would require rebuilding all change pages each time, which would be
+> 100x as slow as the current method.
+>
+> I don't feel that being 100 times faster at the expense of a marginally
+> inconsistent, but still usable interface is a bug. --[[Joey]] [[done]]
--- /dev/null
+I'm using ikiwiki 3.12 on Mac OS X (installed via mac ports)
+
+When trying to rename a file via the web interface (using the rename plugin) I get the following error:
+
+Error: Undefined subroutine &IkiWiki::Plugin::svn::dirname called at /opt/local/lib/perl5/vendor_perl/5.8.9/IkiWiki/Plugin/svn.pm line 246.
+
+Applying the following patch fixed it:
+
+ --- IkiWiki/Plugin/svn.pm.orig 2009-07-08 12:25:23.000000000 -0400
+ +++ IkiWiki/Plugin/svn.pm 2009-07-08 12:28:36.000000000 -0400
+ @@ -243,10 +243,10 @@
+
+ if (-d "$config{srcdir}/.svn") {
+ # Add parent directory for $dest
+ - my $parent=dirname($dest);
+ + my $parent=IkiWiki::dirname($dest);
+ if (! -d "$config{srcdir}/$parent/.svn") {
+ while (! -d "$config{srcdir}/$parent/.svn") {
+ - $parent=dirname($dest);
+ + $parent=Ikiwiki::dirname($dest);
+ }
+ if (system("svn", "add", "--quiet", "$config{srcdir}/$parent") != 0) {
+ warn("svn add $parent failed\n");
+
+
+> Thank you very much for the patch, which I've applied. I wonder how
+> that snuck in (aside from the obvious, that the svn plugin is not often
+> used and the code was added w/o being tested..). [[done]] --[[Joey]]
--- /dev/null
+If I have a <--#include virtual="foo" --> in some file, it gets stripped, even though other HTML comments don't get stripped. I imagine it's some plugin doing it, or IkiWiki itself, or an IkiWiki dependency, but I haven't found where this is happening. I'm trying to implement a workaround for my sidebars forcing a rebuild of the wiki every day - I use the calendar plugin - when the day changes, by using SSI.
+
+> It is probably the [[plugins/htmlscrubber]] plugin. -- [[Jon]]
+
+> htmlscrubber does strip these, because they look like
+> a html tag to it, not a html comment. (html comments start
+> with `<!--` .. of course, they get stripped too, because
+> they can be used to hide javascript..)
+>
+> Anyway, it makes sense for the htmlscrubber to strip server-side
+> includes because otherwise your wiki could be attacked
+> by them being added to it. If you want to use both the htmlscrubber and
+> SSI together, I'd suggest you modify the [[wikitemplates]]
+> and put the SSI on there.
+>
+> Ie, `page.tmpl` has a
+> div that the sidebar is put into; if you just replace
+> that with the SSI that includes your static sidebar,
+> you should be good to go. --[[Joey]]
+
+[[done]]
--- /dev/null
+In ikiwiki 2.66, SVG images are not recognized as images. In ikiwiki.pm,
+the hardcoded list of image file extensions does not include ".svg", which
+it probably should unless there's some other issue about rendering SVGs?
+
+The 'img' plugin also seems to not support SVGs.
+
+> SVG images can only be included via an `<object>`, `<embed>`, or
+> `<iframe>` tag. Or, perhaps as [inline SVG](http://wiki.svg.org/Inline_SVG).
+> The [[plugins/htmlscrubber]] strips all three tags since they can easily
+> be used maliciously. If doing inline SVG, I'd worry that the svg file
+> could be malformed and mess up the html, or even inject javascript. So,
+> the only options seem to be only supporting svgs on wikis that do not
+> sanitize their html, or assuming that svgs are trusted content and
+> embedding them inline. None of which seem particularly palatable.
+>
+> I suppose the other option would be converting the svg file to a static
+> image (png). The img plugin could probably do that fairly simply.
+> --[[Joey]]
+
+>> I'm working on inline SVG and MathML support in ikiwiki and I've
+>> modified my htmlscrubber to sanitize SVG and MathML using the
+>> whitelists from html5lib. Here's a [patch][]. I've also made some
+>> notes about this here: [[todo/svg]].
+>>
+>> I suspect that this bug may have caught the eye of anyone interested
+>> in this sort of thing. I'll elaborate a bit on my user page to avoid
+>> getting off-topic here. --[[JasonBlevins]], October 21, 2008
+
+ [patch]: http://xbeta.org/gitweb/?p=xbeta/ikiwiki.git;a=blobdiff;f=IkiWiki/Plugin/htmlscrubber.pm;h=3c0ddc8f25bd8cb863634a9d54b40e299e60f7df;hp=3bdaccea119ec0e1b289a0da2f6d90e2219b8d66;hb=fe333c8e5b4a5f374a059596ee698dacd755182d;hpb=be0b4f603f918444b906e42825908ddac78b7073
Versions 2.0 and 2.1 of ikiwiki, and I think earlier versions as well,
-allowed wiki links to have spaces in the link text. For example, [[ikiwiki
+allowed wiki links to have spaces in the link text. For example, [[!ikiwiki
logo page|logo]] should create an anchor tag referencing the logo page, and
-[[ikiwiki logo|logo/ikiwiki.png]] should create an image tag referencing
+[[!ikiwiki logo|logo/ikiwiki.png]] should create an image tag referencing
the logo.
As of version 2.2, this no longer works. I think the pattern \\[[...|...]]
> want multiple words.
>
> This was a decision I made a long time ago due to the ambiguity between a
-> WikiLink and a [[ikiwiki/PreProcessorDirective]]. Is "\[[foo bar|baz]]" a wikilink to
+> WikiLink and a [[ikiwiki/Directive]]. Is "\[[foo bar|baz]]" a wikilink to
> baz with a link text of "foo bar", or an instance of preprocessor
> directive "foo" with a parameter of "bar|baz"? If it's interpreted as a
> wikilink today, that could change tomorrow if a new preprocessor directive
>>
>> If there was ever a future, syntax-breaking major release of ikiwiki
>> (similar to python3000) I'd like to see this fixed as part of that.
->> --[[JonDowland]]
+>> --[[users/Jon]]
>>> You can enable `prefix_directives` and get the disambiguated behavior
>>> and spaces in wikilinks today. It will become the default in 3.0.
-[[tag patch]]
+[[!tag patch]]
When a page containing tags and using the [[syntax_(3rd_party)_plugin|plugins/contrib/syntax]] (though pages using other preprocessors may also be affected) is rendered as an inline page, some extra `<p>` elements are added.
> There's a simple patch that can do this:
-> --- a/IkiWiki.pm
-> +++ b/IkiWiki.pm
-> @@ -584,7 +584,7 @@ sub htmllink ($$$;@) { #{{{
-> return "<span class=\"createlink\"><a href=\"".
-> cgiurl(
-> do => "create",
-> - page => pagetitle(lc($link), 1),
-> + page => pagetitle($link, 1),
-> from => $lpage
-> ).
-> "\">?</a>$linktext</span>"
+<pre>
+-- a/IkiWiki.pm
++++ b/IkiWiki.pm
+@@ -584,7 +584,7 @@ sub htmllink ($$$;@) {
+ return "<span class=\"createlink\"><a href=\"".
+ cgiurl(
+ do => "create",
+- page => pagetitle(lc($link), 1),
++ page => pagetitle($link, 1),
+ from => $lpage
+ ).
+ "\">?</a>$linktext</span>"
+</pre>
> This is fine if you don't mind mixed or randomly cased filenames getting
> created. Otoh, if the link happened to start a sentence and so had its
--- /dev/null
+The following renders incorrectly:
+
+ \[[!toc ]]
+
+ # header1
+
+ content1
+
+ # header2
+
+ \[[!map pages="sandbox"]]
+
+
+Removing the `\[[!toc]]` directive or moving it at the end of the page
+makes the whole wiki page be rendered as expected.
+
+Hint : in all cases, the non-interpreted markdown code is copied as-is
+in the HTML output, without any leading `<p>` or any HTML formatting.
+
+> You're using the old version of `markdown`, that is known to have a broken block
+> html parser, that will get confused if markdown is present between two
+> separate html blocks, and not format the markdown.
+>
+> This is fixed in [[!cpan Text::MarkDown]] 1.0.19. markdown 1.0.2 also
+> fixes the problem. Install either one. I'm going to make ikiwiki's
+> dependencies list Text::Markdown before markdown, since people keep
+> stumbling over this. (The downside is that the old broken markdown is
+> faster). --[[Joey]]
+
+[[done]]
--- /dev/null
+I've noticed that Ikiwiki displays URLs with parentheses badly. The problem occurs
+in the latest version 3.00 and older versions. Please look at the link to following
+Polish entry about C programming language at Wikipedia (it seems that URLs with
+parentheses are popular there):
+
+[Język programowania C](http://pl.wikipedia.org/wiki/C_(j%C4%99zyk_programowania))
+
+I need to escape a closing parenthesis of the URL to fix the problem.
+
+[Język programowania C](http://pl.wikipedia.org/wiki/C_(j%C4%99zyk_programowania\))
+
+--[[Paweł|users/ptecza]]
+
+> This is a bug in markdown version 1. It is fixed in [[!cpan Text::Markdown]],
+> which ikiwiki will use if it's installed. [[done]] --[[Joey]]
+
+>> Thanks a lot for the hint, Joey! I've installed `libtext-markdown-perl` package
+>> (Aptitude has removed `markdown` package to satisfy dependencies) and now
+>> I don't need to escape Wikipedia URLs with parentheses :) --[[Paweł|users/ptecza]]
--- /dev/null
+After building a fresh deb from current Git master (9b62dac4bcf62f3a1f76ec5a7ed5a90db16ea1c8) :
+
+ $ ikiwiki --setup ~/ikiwiki.setup --rebuild
+ Undefined subroutine &IkiWiki::refresh called at /usr/share/perl5/IkiWiki/Setup.pm line 113.
+
+> [[done]], it just needed "require IkiWiki::Render" before it started
+> rendering. --[[smcv]]
>> No, apparently FreeBSD `install` does not support `-D`. See [the FreeBSD install manpage](http://www.freebsd.org/cgi/man.cgi?query=install&apropos=0&sektion=0&manpath=FreeBSD+6.2-RELEASE&format=html). --[[JoshTriplett]]
->> Patch applied; [[bugs/done]]. --[[JoshTriplett]]
+>> Patch applied; [[done]]. --[[JoshTriplett]]
+
+There are still/again "cp -a"s in the Makefile as of 3.00
+
+> It's a cp -a || install. Is that causing you a problem somehow?
+> --[[Joey]]
--- /dev/null
+In `IkiWiki::preprocess`, the last capturing group in the regex used to parse directives in prefix_directives mode is of the form `(\s+...)?\]\]`, which will not be matched if the directive is something without arguments or whitespace, like `\[[!orphans]]`. As a result, its value is undef instead of being an empty string, causing a warning when it is used in the anonymous sub `$handle`. A trivial fix is to treat it as "" if it is undef.
+
+[[patch]] in the master branch of my git repository, and quoted here. --[[smcv]]
+
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index 241a7c0..d2c35a2 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -1167,7 +1167,8 @@ sub preprocess ($$$;$$) {
+ }sx;
+ }
+
+ - $content =~ s{$regex}{$handle->($1, $2, $3, $4)}eg;
+ + # $4 can be undef if the directive was \[[!foo]]
+ + $content =~ s{$regex}{$handle->($1, $2, $3, ($4 or ""))}eg;
+ return $content;
+ }
+
+[[cherry-picked|done]] --[[Joey]]
[[bugs/done]] in my sources --[[Joey]]
-Thank you --[[Brix]]
\ No newline at end of file
+Thank you --[[Brix|HenrikBrixAndersen]]
--- /dev/null
+As one can see at [[plugins/more/discussion]], the [[plugins/more]] plugin doesn't work --- it renders as:
+
+ <p><a name="more"></a></p>
+
+ <p>This is the rest of my post. Not intended for people catching up on
+ their blogs at 30,000 feet. Because I like to make things
+ difficult.</p>
+
+No way to toggle visibility.
+-- Ivan Z.
+
+> More is not about toggling visibility. Perhaps you want
+> [[plugins/toggle]] More is about displaying the whole page
+> content when it's a standalone page, and only displaying a fragment when
+> it's inlined into a blog. --[[Joey]] [[done]]
+
+>> I see, thanks for bothering with the reply, I didn't understand this. --Ivan Z.
>>
>> I hope that's just a minor blemish. --liw
+>>> Sounds like this is [[done]] --[[Joey]]
> > `<br/>` is also valid, so this is a bug still. --[[madduck]]
->>> It _is_ the htmlscrubber that removes that. It's due to [[debbug 365971]],
->>> basically the [[cspan HTML::Scrubber]] doesn't understand xhtml tags
+>>> It _is_ the htmlscrubber that removes that. It's due to [[!debbug 365971]],
+>>> basically the [[!cspan HTML::Scrubber]] doesn't understand xhtml tags
>>> of this sort at all, I hacked it to support `<br />` by tellig it to treak
>>> the "/" as an attribute, but if there's no space, it doesn't see it as
>>> an attribute. Hmm, I could also add `br` as a tag name, that would catch both cases.
> 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]]
--- /dev/null
+[[plugins/aggregate]] takes a name parameter that specifies a global name
+for a feed. This causes some problems:
+
+* If a site has multiple pages that aggregate, and they use the same
+ name, one will win and get the global name, the other will claim it's
+ working, but it's really showing what the other aggregated.
+* If an aggregate directive is moved from page A to page B, and the wiki
+ refreshed, aggregate does not realize the feed moved, and so it will
+ keep aggregated pages under `A/feed_name/*`. To work around this bug,
+ you have to delete A, refresh (maybe with --aggregate?), and then add B.
+
+Need to find a way to not make the name be global. Perhaps it needs to
+include the name of the page that contains the directive?
> This is a bug in XML::Parser. Unfortunately, perl does not have a feed
> parser that handles invalid feeds, and in particular, XML::Parser has
> issues with feeds that claim to be encoded in utf-8 and contain invalid
-> utf sequences, as well as other encoding issues. See also [[debbug 380426]].
+> utf sequences, as well as other encoding issues. See also [[!debbug 380426]].
> Note though that this invalid feed does not really crash the aggregate plugin,
> it just notes that XML::Parser crashed on it and continues. This is the
> best I can do in ikiwiki. I have filed a bug on XML::Parser about this,
-> it's [[debbug 420636]]. I've also put in a workaround, so [[done]].
+> it's [[!debbug 420636]]. I've also put in a workaround, so [[done]].
**Wonderful**, thanks Joey! -- Adam.
if defined $mtime && $mtime <= time;
>> I'll have to debug this, it's not working here... and this is an ikiwiki aggregator scraping another ikiwiki site.
+
+>>> Any news about this? --[[Joey]]
[[!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.
--- /dev/null
+I've just noticed that `attachment` plugin escapes the underscore
+characters in attached filenames. For example, when I wanted to add
+`foo_bar_baz.txt` file, then Ikiwiki added file `foo__95__bar__95__baz.txt`
+to my Subversion repo. I hope that the filename is terribly ugly not only
+for me ;)
+
+Is it a bug or security feature? --[[Paweł|ptecza]]
+
+>> Update: It's not only problem with attached filenames. I have
+>> `mysql/myisam_vs_ndb.mdwn` page in my wiki and attached two
+>> images (`myisam_vs_ndb_sql.png` and `myisam_vs_ndb_cpu.png`)
+>> and one OpenDocument file (`myisam_vs_ndb.ods`). Ikiwiki placed
+>> them into `myisam__95__vs__95__ndb` subdirectory as
+>> `myisam__95__vs__95__ndb__95__sql.png`, `myisam__95__vs__95__ndb__95__cpu.png`
+>> and `myisam__95__vs__95__ndb.ods` files. When I click "Attachments" link,
+>> I can't see my uploaded files, because there are in another subdirectory
+>> (`myisam__95__vs__95__ndb` instead of `myisam_vs_ndb`). --[[Paweł|ptecza]]
+
+> [[done]], uses `linkpage` now.
+
+>> It's seems that now Ikiwiki doesn't escape the filenames with underscore(s).
+>> Thank you very much for the fast fix! --[[Paweł|ptecza]]
--- /dev/null
+I can't add any attachment to my wiki. When I select file using "Browse"
+button and click "Upload Attachment", then `ikiwiki.cgi` file displays
+the error message like below:
+
+ Błąd: failed to get filehandle
+
+> Can you do some debugging? If you edit attachment.pm line 136, to print
+> out what it did get, and show me what that yields, maybe I can figure
+> this out.
+
+ error("failed to get filehandle ($fh)");
+
+>> Sure. I've done the change and it seems that $fh variable is undefined:
+
+>> Use of uninitialized value in concatenation (.) or string at /usr/share/perl5/IkiWiki/Plugin/attachment.pm line 135.
+>> failed to get filehandle ()
+
+> Also, what web server and version of perl is this? --[[Joey]]
+
+>> It's Apache2 2.2.8-1ubuntu0.3 and Perl 5.8.8-12 from Ubuntu Hardy. --[[Paweł|ptecza]]
+
+>>> Hmm, is your CGI.pm perhaps creating the attachment temp file, but
+>>> not providing an open filehandle to it via the `upload` method?
+>>> Change the debugging line to this: --[[Joey]]
+
+ error("failed to get filehandle:$fh ; file:$filename ; is ref:".ref($q->param('attachment')));
+
+>>>> Now my Ikiwiki returns:
+
+>>>> failed to get filehandle: ; file:sandbox/test.txt ; is ref:
+
+>>>> Is it helpful for you? --[[Paweł|ptecza]]
+
+>>>>> Yes, this suggests that CGI.pm's `upload` function is not working,
+>>>>> but that it *is* returning a filehandle pointing at the attachment
+>>>>> using the old method. Hmm, so I'll bet you have a CGI.pm version
+>>>>> older than 2.47. Can you find your system's CGI.pm and grep for
+>>>>> "VERSION" in it to determine the version? I checked debian stable.
+>>>>> and its perl 5.8.8 has version 3.15, so is not affected, I think.
+
+>>>>>> I have CGI.pm 3.15 too:
+
+>>>>>> $ grep VERSION= /usr/share/perl/5.8.8/CGI.pm
+>>>>>> $CGI::VERSION='3.15';
+
+>>>>> I've just checked in a fix that should work, can you test it?
+>>>>> [diff](http://git.ikiwiki.info/?p=ikiwiki;a=commitdiff;h=71f10579c00a8ddc20ada1a1efd33aac25a3da7e) --[[Joey]]
+
+>>>>>> I've patched `attachment.pm` module, but the bug still occurs.
+>>>>>> However I can see a little progress. I changed invoking `error()`
+>>>>>> subroutine like you showed me before and now Ikiwiki prints
+
+>>>>>> failed to get filehandle:test.txt ; file:sandbox/test.txt ; is ref:
+
+>>>>>> --[[Paweł|ptecza]]
+
+>>>>>>> Well then, your CGI.pm is somehow not behaving as its documentation
+>>>>>>> describes, in two ways:
+>>>>>>> 1. `upload()` is not returning a reference to the filehandle
+>>>>>>> 2. The filename returned by `param("attachment")` is not also
+>>>>>>> a file handle.
+>>>>>>> That seems very broken. I can try to work around it some more
+>>>>>>> though. I've checked in a second try at dealing with things, can
+>>>>>>> you try it? --[[Joey]]
+
+>>>>>>>> Do you mean that [diff](http://git.ikiwiki.info/?p=ikiwiki;a=commitdiff;h=66f35e30dcea03c631a293e2341771277543b4ae)?
+>>>>>>>> If so, then it causes "Internal Server Error" for me:
+
+>>>>>>>> Can't use string ("test.txt") as a symbol ref while "strict refs" in use at /usr/share/perl5/IkiWiki/Plugin/attachment.pm line 144.
+
+>>>>>>>> I can rebuild Debian stable source package with CGI for Perl. Maybe it will help me? What do you think? --[[Paweł|ptecza]]
+
+>>>>>>>>> Silly thinko on my part, fixed that in git.. --[[Joey]]
+
+>>>>>>>>>> Thanks for the fix, Joey! Now CGI doesn't fails, but still no success with attaching file:
+
+>>>>>>>>>> failed to open : No such file or directory
+
+>>>>>>>>>> Do you have any another idea how to resolve that problem? I can try with rebuilding
+>>>>>>>>>> package `perl-modules` if it's necessary in that situation. --[[Paweł|ptecza]]
+
+>>>>>>>>>>> If CGI.pm is not creating a temp file, not providing a
+>>>>>>>>>>> filehandle by either of its documented methods, then it's just
+>>>>>>>>>>> broken; ikiwiki can't deal with that level of brokennecess.
+>>>>>>>>>>> I need to find out if this affects stable in general, or just
+>>>>>>>>>>> you/ubuntu. --[[Joey]]
+
+>>>>>>>>>>>> Same thing on FreeBSD using CGI.pm 3.15. Looks like $self->{'.tmpfiles'} in CGI.pm
+>>>>>>>>>>>> is not populated with the information about the uploaded file, causing tmpFileName()
+>>>>>>>>>>>> to return '' (unloadInfo(), which uses the same lookup method fails in the same manner),
+>>>>>>>>>>>> but I have yet to find out why this happens. --[[HenrikBrixAndersen]]
+
+The same message I can see in the Apache log file. There is also
+following warning:
+
+ Use of uninitialized value in length at /usr/share/perl5/IkiWiki/Plugin/attachment.pm line 36.
+
+> This is unrelated, I've fixed the warning message. --[[Joey]]
+
+Is it Ikiwiki bug or my attachment plugin is misconfigured? --[[Paweł|ptecza]]
+
+> I've reproduced the bug, and it does seem to be a bug with the perl in
+> debian stable/ubuntu hardy. Trying to figure it out --[[Joey]]
+
+> This was amazingly disgusting, see commit message for the full horror of
+> the details. I think it's [[done]] -- at least it works on debian stable
+> now. --[[Joey]]
+
+>> Wow! It's probably the biggest Ikiwiki commit message I've ever seen :)
+
+>> Yes, I can confirm that now the plugin works for me and I'm able to add
+>> attachments to my wiki. Yupiii! :D
+>> Thanks a lot, Joey! You're really great! :) --[[Paweł|ptecza]]
+
+>> Thank you very much for your effort, Joey! :) --[[Paweł|ptecza]]
At [[attachment|plugins/attachment]] plugin page I can see
that it's enabled by default in Ikiwiki. Is it true?
-> No, typo. I don't want to enable it by default because it requires
+> No, typo ([[done]]). I don't want to enable it by default because it requires
> site-specific configuration to be made secure. --[[Joey]]
+>> Thanks for your reply! I was guessing it :) --[[Paweł|ptecza]]
+
I have backported Ikiwiki 2.52 and I need to add that plugin to
`add_plugins` variable in my `ikiwiki.setup` file (and rebuild
my wiki, of course) to see new upload buttons when I edit a page
> FWIW, you don't need to rebuild the whole wiki, --refresh --wrappers is enough.
+>> It's good to know. Thank you for the hint!
+
Maybe should I enable attachment handling in different way?
--[[Paweł|users/ptecza]]
--- /dev/null
+I was just hovering over the '...' next to the backlinks on a page on
+<http://ikiwiki.info/>. In terms of the size of my browser window, this was
+towards the bottom-right of the screen.
+
+When I hovered over the '...', the additional backlinks float appeared. This
+caused the page length to grow down, meaning a horizontal scrollbar was added
+to the page. This meant the text reflowed, and the '...' moved outside of my
+mouse pointer region.
+
+This caused an infinite loop of box appears... text moves, box disappears...
+box re-appears.. which was not very visually pleasant.
+
+In general I think that the onhover float is a bit of bad UI. Even a truncated
+list of backlinks looks cluttered due to there being no delimiters. I moved to
+having an always-complete list of backlinks and having them as LI elements
+inside a UL to make it look neater, although I appreciate that would make some
+pages very long indeed.
+
+How about doing something a little like [[plugins/toggle]] for the excess
+items instead?
+
+-- [[Jon]]
+
+----
+
+An additional, related issue: if the box expands beyond the bottom of the
+page, you might move your mouse pointer to the scrollbar in order to move
+further down the list, but of course then you are outside the hover region.
+
+-- [[Jon]]
+
+> I agree, browser handling of this CSS is often not good.
+>
+> A toggle would be the perfect UI, but the heaviness of needing
+> to include 30 lines of javascript to do it, plus then it only working
+> with javascript enabled, is also not optimal.
+>
+> Another idea would be to make the "..." a link to the ikiwiki cgi.
+> The cgi could then have a mode that displays all the backlinks of a page
+> in a list.
+>
+> Yet another idea: Find some more refined CSS for handling a variable
+> size popup.. --[[Joey]]
--- /dev/null
+I have a commit doing
+
+ -\[[map pages="link(tag/<TMPL_VAR name>) and !papers/*"]]
+ +\[[map pages="link(sourcepage()) and !papers/*"]]
+
+ikiwiki now fails to compile the site, barfing:
+
+ Use of uninitialized value in subroutine entry at /usr/share/perl5/IkiWiki.pm line 1288.
+ ikiwiki.setup: Can't use string ("") as a subroutine ref while "strict refs" in use at /usr/share/perl5/IkiWiki.pm line 1288.
+ BEGIN failed--compilation aborted at (eval 6) line 200.
+
+after forcefully entering the Perl mode of thinking, I reduced this to line
+1285 of IkiWiki.pm (2.53), which apparently returns `undef`:
+
+ my $sub=pagespec_translate($spec);
+
+Why does it even bother parsing the diffs of `recentchanges`?
+
+I have not recompiled this site in ages, so I am not sure when this problem
+was introduced, but it wasn't there when I worked on the site last about
+a year ago in September 2007.
+
+-- [[madduck]]
+
+> I can't reproduce this problem. When I try, the generated
+> `recentchanges/change_$sha1._change` file has the diff properly escaped,
+> so that the map is not expanded at all.
+>
+> I also tried de-escaping that, and still failed to reproduce any crash.
+> The bogus pagespec simply expands to nothing. The line directly after the
+> line you quoted checks for syntax errors in the pagespec translation
+> eval and seems to be working fine:
+>
+> joey@kodama:~>perl -e 'use IkiWiki; my
+> $sub=IkiWiki::pagespec_translate("link(tag/<TMPL_VAR name>) and !papers/*"); print "caught failure:".$@'
+> caught failure:syntax error at (eval 14) line 1, near "|| &&"
+>
+> Based on your line numbers, you are not running a current version of
+> ikiwiki. (Doesn't quite seem to be version 2.53.x either) Try with a current
+> version, and see if you can send me a source tree that can reproduce the
+> problem? --[[Joey]]
--- /dev/null
+[[plugins/meta]] is not enabled by default, yet some pages in the default basewiki include [[the_meta_directive|ikiwiki/directive/meta]], notably the [[ikiwiki]] heirarchy.
+
+This means that the default output of "ikiwiki src dest", for two empty directories src and dest, result in the meta directive being displayed inline with the page text.
+
+> [[done]], meta now enabled by default.
--- /dev/null
+beautify_urlpath will prepend a useless "./" to the URL "./foo". Fixed in commit 5b1cf21a on my comments branch. --[[smcv]]
+
+[[!tag patch done]]
>>>> However, the part that seems a bit wrong to me, is this: even if my locale is utf8, I have to explicitly set a utf8 locale in the wiki's setup file, or the commit fails. It looks like ikiwiki is not using this machine's default locale, which is utf8. Also, I'm not getting any errors on apache's error log.
>>>> Wouldn't it make sense to use the machine's default locale if 'locale' is commented out in the setup file?
+
+>>>>> Ikiwiki wrappers only allow whitelisted environment variables
+>>>>> through, and the locale environment variables are not included
+>>>>> currently.
+>>>>>
+>>>>> But that's not the whole story, because "machine's default locale"
+>>>>> is not very well defined. For example, my laptop is a Debian system.
+>>>>> It has a locale setting in /etc/environment (`LANG="en_US.UTF-8"`).
+>>>>> But even if I start apache, making sure that LANG is set and exported
+>>>>> in the environment, CGI scripts apache runs do not see LANG in their
+>>>>> environment. (I notice that `/etc/init.d/apache` explocitly
+>>>>> forces LANG=C. But CGI scripts don't see the C value either.)
+>>>>> Apache simply does not propigate its runtime environment to CGI
+>>>>> scripts, and this is probably to comply with the CGI specification
+>>>>> (although it doesn't seem to completly rule out CGI's being passed
+>>>>> other variables).
+>>>>>
+>>>>> If mercurial needs a utf-8 locale, I guess the mercurial plugin needs
+>>>>> to check if it's not in one, and do something sane (either fail
+>>>>> earlier, or complain, or strip utf-8 out of comments). --[[Joey]]
--- /dev/null
+When using monotone as revision control system, a "mtn: operation canceled: Broken pipe" message is printed. Reason is that, in a call to mtn, the pipe is closed before mtn has done all its output. This patch fixes the problem.
+
+ diff -up ikiwiki/IkiWiki/Plugin/monotone.pm.orig ikiwiki/IkiWiki/Plugin/monotone.pm
+ --- ikiwiki/IkiWiki/Plugin/monotone.pm.orig 2008-11-12 23:45:24.000000000 +0100
+ +++ ikiwiki/IkiWiki/Plugin/monotone.pm 2008-12-16 12:41:38.000000000 +0100
+ @@ -525,13 +525,12 @@ sub rcs_recentchanges ($) {
+ my $child = open(MTNLOG, "-|");
+ if (! $child) {
+ exec("mtn", "log", "--root=$config{mtnrootdir}", "--no-graph",
+ - "--brief") || error("mtn log failed to run");
+ + "--brief", "--last=$num") || error("mtn log failed to run");
+ }
+
+ - while (($num >= 0) and (my $line = <MTNLOG>)) {
+ + while (my $line = <MTNLOG>) {
+ if ($line =~ m/^($sha1_pattern)/) {
+ push @revs, $1;
+ - $num -= 1;
+ }
+ }
+ close MTNLOG || debug("mtn log exited $?");
+
+> Thanks for the patch, and for testing the monotone backend.
+> applied [[done]] --[[Joey]]
--- /dev/null
+Using bzr, the dates for changes on the RecentChanges page all start
+slightly before the Unix epoch.
+
+Changing line 249 of bzr.pm from
+
+` when => time - str2time($info->{"timestamp"}),`
+
+to
+
+` when => str2time($info->{"timestamp"}),`
+
+fixed this for me.
+
+> Weird, I wonder why it was written to return an absolute time like that
+> in the first place? Can't have ever been right. Fixed, thanks. --[[Joey]]
+> [[done]]
--- /dev/null
+The bzr plugin does not seem to define the rcs_diff subroutine.
+I got the follow error after enabling recentchangesdiff:
+
+"Undefined subroutine &IkiWiki::Plugin::bzr::rcs_diff called at /usr/share/perl5/IkiWiki.pm line 1590."
+
+Grepping to verify absence of rcs_diff:
+
+ $ grep rcs_diff /usr/share/perl5/IkiWiki/Plugin/{git,bzr}.pm
+ /usr/share/perl5/IkiWiki/Plugin/git.pm: hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+ /usr/share/perl5/IkiWiki/Plugin/git.pm:sub rcs_diff ($) {
+ /usr/share/perl5/IkiWiki/Plugin/bzr.pm: hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff);
+
+> I've added the minimal stub needed to avoid the crash, but for
+> recentchangesdiff to work, someone needs to implement `rcs_diff` for bzr.
+> This should be trivial if you know and use bzr. The function
+> is passed as a parameter the revno of interest and just needs
+> to ask bzr for the diff between that and the previous version. --[[Joey]]
+
+>> I'll see if I can make a patch. The bzr command to get the revision would
+>> look like this: bzr diff -r revno:$PREV:/path/to/src..revno:$REVNO:/path/to/src
+>> (where $PREV would be $REVNO minus one). --liw
+
+>> Sorry, that was not entirely correct, for some reason. I'll add a patch below that
+>> seems to work. I am unfortunately not ready to set up a git repository that you
+>> can pull from. --liw
+
+[[done]] --[[Joey]]
--- /dev/null
+Shortcuts such as \[[!google foo]] do not work when previewing pages.
+--[[JasonBlevins]]
+
+> Broken during the setup dumping changes, now fixed. --[[Joey]] [[done]]
+
+>> Just a quick note that this fix interacts with the way the `listdirectives`
+>> directive gets its list of non-shortcut directives. At the moment it
+>> still works, but it relies on the fact that the `listdirectives` `checkconfig`
+>> hook is called before the `shortcut` `checkconfig` hook.
+>> -- [[Will]]
+
+>> The order plugins are loaded is effectively random. (`keys %hooks`).
+>> So I've made shortcuts pass a 'shortcut' parameter when registering
+>> them, which listdirectives can grep out of the full list of directives.
+>> That may not be the best name to give it, especially if other plugins
+>> generate directives too. Seemed better than forcing shortcut's
+>> checkconfig hook to run last tho. --[[Joey]]
--- /dev/null
+meta title cannot reliably be put inside a template used by the
+[[plugins/template]] plugin. Since meta title info is gathered in the scan
+pass, which does not look at the template a page includes, it will not be
+seen then, and so other pages that use the page title probably won't use
+it. (Barring luck with build order.)
+
+Update: This also affects using tags from templates.
+
+There is a simple fix for this, just add `scan => 1` when registering the
+preprocess hook for the template plugin.
+
+However, the overhead of this has to be considered. It means that, on every
+scan pass, every page containing a template will cause the template to be
+loaded and filled out. This can be some serious additional overhead.
+
+--[[Joey]]
+
+[[done]]
--- /dev/null
+> Joey, please fix the colon in page name of my report. Ikiwiki sets
+> "attachment:\_failed\_to\_get\_filehandle/" URL on "Bugs" page and
+> the report is not clickable in my Epiphany browser:
+
+> Firefox doesn't know how to open this address, because the protocol
+> (attachment) isn't associated with any program.
+
+> I can only edit it :) Bad handling ':' character by Ikiwiki is probably
+> its another bug.
+> --[[Paweł|ptecza]]
+
+> [[fixed|done]] in git (but fix is not live on here as of this writing) --[[Joey]]
--- /dev/null
+testing a link to [[colon:problem]]
--- /dev/null
+Comments produce links like `sandbox/comment_1` in [[RecentChanges]], which,
+when clicked, redirect to a page that does not exist.
+
+The `recentchanges` branch in my repository contains one possible [[patch]],
+which causes the CGI to go to the [[ikiwiki/directive/meta]] `permalink`, if
+any, if the page is internal (comments do have a permalink).
+
+> [[done]].. I I had thought about not showing internal page changes at
+> all, but I like your approach better --[[Joey]]
--- /dev/null
+Example (from [here](http://git.ikiwiki.info/?p=ikiwiki;a=blobdiff;f=doc/todo/matching_different_kinds_of_links.mdwn;h=26c5a072bf3cb205b238a4e6fd0882583a0b7609;hp=1d7c78d9065d78307b43a1f58a53300cde4015fa;hb=9b4c83127fdef0ceb682c104db9bfb321b17022e;hpb=df4cc4c16ca230ee99b80c80043ba54fb95f6e71)):
+<pre>
+[[`\[[!taglink TAG\]\]`|plugins/tag]]
+</pre>
+gives:
+
+[[`\[[!taglink TAG\]\]`|plugins/tag]]
+
+Expected: there is a [[ikiwiki/wikilink]] with the complex text as the displayed text. --Ivan Z.
[[done]] --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
--- /dev/null
+If the timeformat option is '%c', every time websetup rewrites the setup file, it changes to a ddate-style time format (but if ddate is not actually enabled, some of the format codes aren't understood by strftime, so they get passed through).
+
+Presumably this is because websetup loads all plugins, so IkiWiki::plugin::ddate::checkconfig is run...
+
+(This bug seems oddly appropriate. Hail Eris)
+
+[[done_fnord|done]]
-`\[[debbug 123456]]` expands to "bug #123456", which is hyperlinked. Could you please drop the leading "bug", for two reasons?
+`\[[!debbug 123456]]` expands to "bug #123456", which is hyperlinked. Could you please drop the leading "bug", for two reasons?
First, #123456 is not a bug, it's a bug report. And second, #123456 suffices, doesn't it? By hardcoding the "bug" in there, you make it impossible to start a sentence with a bug number, e.g.:
--- /dev/null
+Adding text of the format
+
+ Apple
+ : Pomaceous fruit of plants of the genus Malus in
+ the family Rosaceae.
+ : An american computer company.
+
+ Orange
+ : The fruit of an evergreen tree of the genus Citrus.
+
+Does not result in expected HTML as described in the [MultiMarkdown Syntax Guide](http://fletcherpenney.net/multimarkdown/users_guide/multimarkdown_syntax_guide/):
+
+Should be
+
+ <dl xmlns="http://www.w3.org/1999/xhtml">
+ <dt>Apple</dt>
+ <dd>
+ <p>Pomaceous fruit of plants of the genus Malus in
+ the family Rosaceae.</p>
+ </dd>
+ <dd>
+ <p>An american computer company.</p>
+ </dd>
+ <dt>Orange</dt>
+ <dd>
+ <p>The fruit of an evergreen tree of the genus Citrus.</p>
+ </dd>
+ </dl>
+
+But instead it gives:
+
+ <p>Apple
+ : Pomaceous fruit of plants of the genus Malus in
+ the family Rosaceae.
+ : An american computer company.</p>
+
+ <p>Orange
+ : The fruit of an evergreen tree of the genus Citrus.</p>
+
+> ikiwiki's markdown support does not include support for multimarkdown by
+> default. If you want to enable that, you can turn on the `multimarkdown`
+> option in the setup file. --[[Joey]]
+
+>> Sorry, I should have indicated, I have multimarkdown enabled:
+
+ # mdwn plugin
+ # enable multimarkdown features?
+ multimarkdown => 1,
+
+>>Other features appear to be working, tables and footnotes for instance. See current install: <http://wiki.infosoph.org>
+
+>>> Ok, in that case it's a bug in the perl module. Forwarded to
+>>> <http://github.com/bobtfish/text-markdown/issues#issue/6> --[[Joey]]
+>>> [[!tag done]]
> Yes, it only controls the number of backlinks that are shown at the
> bottom of the page vs how many are moved to the popup. I've tried to
> improve the documentation for this. [[done]] --[[Joey]]
+
+
+I notice that there is quite a bit of redundancy when both tags and
+backlinks are used extensively. On most pages, the set of links features in
+both categories is almost identical because a tag's index page is shown
+both as a tag link and as a backlink. Is there a way to improve that
+situation somehow? I realise that backlinks aren't generated when the tag
+index page refers to its contents by \[\[!map ...]], etc., but sometimes an
+auto-generated index is insufficient.
+
+ --Peter
+
+> Um, if you're manually linking from the tag's page to each page so
+> tagged, I think you have larger problems than tags and backlinks being
+> the same. Like keeping that list of links up to date as tags are added
+> and changed. --[[Joey]]
+
+I see your point, Joey. I need to maintain that list manually, though, because the automatically generated list is too brief. \[[!map ...]] generates just a list of titles or descriptions. I need a list that contains both. See [[this_posting|ikiwiki/directive/map/discussion]] for more details. Until \[[!map]] can do that, I'm stuck with a manually maintained list. Which means that every link shows up in the backlinks.
recently fixed [[bugs]]
-[[inline pages="link(bugs/done) and !bugs and !*/Discussion" sort=mtime show=10]]
+[[!inline pages="link(bugs/done) and !bugs and !*/Discussion" sort=mtime show=10]]
--- /dev/null
+Calling ikiwiki with a bunch of options, including the --dumpsetup somefile.setup option creates somefile.setup for later reuse with the --setup option. The destination dir however is not saved in the setup file, it has destdir => ''.
+
+> that broke in version 2.64 .. fixed [[done]] --[[Joey]]
--- /dev/null
+I'm editing /posts/foo. If I create a link to a subpage (in my case,
+"discussion"), and hit preview, it gets resolved to /discussion, not
+/posts/foo/discussion. If I hit commit, the latter happens. This seems like
+a bug. --liw
+
+> That would be a bug, but I cannot reproduce it. For example, I edited
+> <http://kitenet.net/~joey/blog/entry/wikis_out_of_disk/> and added a
+> discussion link and on preview it went to the page's discussion page. I
+> don't normally have a toplevel /discussion page, but I also tried adding
+> one, and the link still doesn't link to it. Testcase? --[[Joey]]
+
+>> I can reproduce this on <http://blog.liw.fi/posts/distributed-internet-witness-service/>:
+>> if I edit the page, then preview (no changes made), the "discussion" link at the bottom
+>> of the page points in the preview
+>> to <http://blog.liw.fi/discussion/>,
+>> whereas the saved page has it pointing to
+>> <http://blog.liw.fi/posts/distributed-internet-witness-service/discussion/>.
+>> I'll arrange so that you can edit the page to test this.
+>> --liw
+
+>> Joey suggested my wiki might be missing the FORCEBASEURL snippet from the misc.tmpl
+>> template, and he's right. Mea culpa: I had not diffed the various templates when upgrading
+>> and had missed that updated. [[done]] --liw
--- /dev/null
+A [[PageSpec]] that is entirely negated terminals, such as "!foo and !bar"
+matches all other pages, including all internal pages. This can lead to
+unexpected results, since it will match a bunch of recentchanges pages,
+etc.
+
+Recall that internal-use pages are not matched by a glob. So "\*" doesn't
+match them. So if the pagespec is "\* and !foo and !bar", it won't match
+them. This is the much more common style.
+
+There's an odd inconsistency with entirely negated pagespecs. If "!foo"
+matches page bar, shouldn't "" also match bar? But, the empty pagespec is
+actually special-cased to not match anything.
+
+Indeed, it seems what would be best would be for "!foo" to not match any
+pages, unless it's combined with a terminal that positively matches pages
+("* and !foo"). Although this would be a behavior change, with transition
+issues.
+
+Another approach would be to try to detect the case of an entirely negated
+pagespec, and implicitly add "and !internal()" to it.
+
+Either approach would require fully parsing the pagespec. And consider cases
+like "!(foo and !bar)". Doesn't seem at all easy to solve. --[[Joey]]
+
+> It occurs to me that at least one place in ikiwiki optimizes by assuming
+> that pagespecs not mentioning the word "internal" never match internal
+> pages. I wonder whether this bug could be solved by making that part of
+> the definition of a pagespec, rather than a risky optimization
+> like it is now? That seems strange, though - having this special case
+> would make pagespecs significantly harder to understand. --[[smcv]]
--- /dev/null
+I created an image and a mdwn with an ampersand in the filename.
+This gaves me some error messages.
+I renamed the files and committed.
+
+> Ikiwiki does not allow files containing ampersands or most other non-alphanumeric characters.
+> It will display a "skipping bad filename" warning if you have such files. --[[Joey]]
+
+Even now, I still get the following error messages:
+
+ Use of uninitialized value in substitution (s///) at /usr/lib64/perl5/vendor_perl/5.8.8/IkiWiki.pm line 764.
+ Use of uninitialized value in substitution (s///) at /usr/lib64/perl5/vendor_perl/5.8.8/IkiWiki.pm line 768.
+ Use of uninitialized value in concatenation (.) or string at /usr/lib64/perl5/vendor_perl/5.8.8/IkiWiki.pm line 773.
+ Use of uninitialized value in concatenation (.) or string at /usr/lib64/perl5/vendor_perl/5.8.8/IkiWiki.pm line 773.
+ Use of uninitialized value in concatenation (.) or string at /usr/lib64/perl5/vendor_perl/5.8.8/IkiWiki.pm line 773.
+ Use of uninitialized value in concatenation (.) or string at /usr/lib64/perl5/vendor_perl/5.8.8/IkiWiki.pm line 773.
+
+> To help with this I'd need to know, at a minimum, what version of ikiwiki you're using,
+> and I'd really also probably need a copy of the source of the wiki you are trying to
+> build with it. (If you'd like to email me a tarball, send it to joey@kitenet.net) --[[Joey]]
+
+> > Hmm... the most recent ikiwiki seems to fix the issue, so I will mark it as [[done]]. --[[JosephTurian]]
--- /dev/null
+The standalone 'markdown' utility is perfectly happy with an external link inside a `<h1>`, e.g.:
+
+ # Review of [Dwarf Fortress][]
+ ...
+ [Dwarf Fortress]: http://www.bay12games.com/dwarves/
+
+produces
+
+ <h1>Review of <a href="http://www.bay12games.com/dwarves/">Dwarf Fortress</a></h1>
+
+but when I try to use this construct in an ikiwiki page, I get
+
+ <h1>Review of [Dwarf Fortress][]</h1>
+
+It works fine with h2 and deeper. The square brackets also appear in the output of an [[ikiwiki/directive/inline]] directive in archive mode, I haven't tried non-archive mode.
+
+> I think you were confused by markdown's slightly wacky mix of square brackets and parens.
+> The url in a markdown link goes in parens, not square brackets. For example:
+
+# [Google](http://google.com/)
+
+> [[done]] --[[Joey]]
+
+>> It works here but it definitely does *not* work on my wiki; but on further experimentation, I believe my problem is being caused by JasonBlevins' [h1title](http://code.jblevins.org/ikiwiki/plugins.git/plain/h1title.pm) plugin.
--- /dev/null
+[[!meta title="feedfile does the wrong thing from index"]]
+
+When I put the following !inline in my index.mdwn, it generate a file called index/graphics.rss. However, the link in the RSS button is to graphics.rss (i.e., not in the index/ directory).
+
+`\[[!inline pages="link(tags/graphics) and ./posts/* and !*/Discussion" show="10" feedfile=graphics feedonly=yes]]`
+
+[[done]] --[[Joey]]
--- /dev/null
+I'm using firefox-3.0.8-alt0.M41.1 (Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4pre) Gecko/2008100921 Firefox/3.0). I have noticed that quite often it shows an old state of a page at http://ikiwiki.info, e.g., [[recentchanges]] without my last edits, or the last page I edited (say, 50 min ago) in the state it was before I edited it.
+
+Only explicitly pressing "reload" helps.
+
+Is it a bug? I haven't been noticing such problems usually on other sites. --Ivan Z.
> This is a bug in markdown, not in ikiwiki. Markdown often has issues with
> one sort of list followed by a second sort. I've filed a bug report on
-> markdown about this ([[debbug 432152]])
+> markdown about this ([[!debbug 432152]])
> (BTW, this bug was filed by editing the bugs page directly. Please don't
> do that, use the form to generate a new per-bug page..)
>>> setting, or one in the environment will be ignored. (This is done for
>>> security since ikiwiki can be run setuid.) If you need to use
>>> a nonstandard path, you'll need to edit that. --[[Joey]]
+
+[[!tag done]]
--- /dev/null
+I've just been getting ikiwiki running on a hosted server. The server is wrapping all cgi scripts to 'harden' them. Unfortunately, that script is sensitive to what a cgi script outputs on stderr.
+
+Ikiwiki's git handling is sending a bunch of output to stderr. The following patch closes stderr in the child process that ikiwiki forks to run git. This allows me to use ikiwiki on this hosted server. (patch inline - check source to get it)
+
+ diff --git a/IkiWiki/Rcs/git.pm b/IkiWiki/Rcs/git.pm
+ index 425536f..5734bb2 100644
+ --- a/IkiWiki/Rcs/git.pm
+ +++ b/IkiWiki/Rcs/git.pm
+ @@ -24,6 +24,7 @@ sub _safe_git (&@) {
+ if (!$pid) {
+ # In child.
+ # Git commands want to be in wc.
+ + open STDERR, '>/dev/null';
+ chdir $config{srcdir}
+ or error("Cannot chdir to $config{srcdir}: $!");
+ exec @cmdline or error("Cannot exec '@cmdline': $!");
+
+> This sounds like rather counter-productive "hardening" (making life harder
+> for real users without any security improvement that I can think of),
+> but if you have to suppress standard error of the CGI,
+> can't you just replace ikiwiki.cgi with this...
+>
+> #!/bin/sh
+> exec /some/where/else/ikiwiki.cgi "$@" 2>/dev/null
+>
+> or (if you're constrained to Perl) this?
+>
+> #!/usr/bin/perl
+> open STDERR, '>/dev/null';
+> exec ("/some/where/else/ikiwiki.cgi", @ARGV);
+>
+> (Also indented all the lines of your patch so markdown won't eat it :-) )
+> --[[smcv]]
+
+> Right, I don't like throwing stderr away because stderr is supposed to be
+> logged to error.log for a reason: To allow debugging problems.
+> It's unfortunate that git [abuses atderr](http://bugs.debian.org/447395),
+> outputting non-errors to it. That doesn't mean that git might not also
+> output actual error messages there. --[[Joey]]
+
+>> I'm happy with the wrapper script solution, so this is [[done]].
+>> And this report is now here to point others to that solution.
> I don't see one, except for diffs that show all changes in the commit,
> rather than only changes to a single file. This feels like a bug in
> gitweb. --[[Joey]]
+
+This is fixed by using the new gitweb style urls. Which new gitweb
+requires, but is a manual change you have to make in your setup. So,
+[[done]] --[[Joey]]
> I don't see any way to make gitweb do that. You can click on the filename
> after the "diff -cc" to see the whole file output, but gitweb won't show
> a diff for a newly added file. --[[Joey]]
+
+>> happily this, too, is fixed by using the new style gitweb urls. [[done]]
+>> --[[Joey]]
--- /dev/null
+If goto is passed a page name that
+contains spaces or is otherwise not a valid page name,
+it will display a "page does not exist", with a create link. But,
+clicking on the link will result in "bad page name".
+
+I have found at least two ways it can happen:
+
+* If 404 is enabled, and the user goes to "http://wiki/some page with spaces"
+* If mercurial is used, it pulls the user's full name, with spaces,
+ out for `rcs_recentchanges` and that ends up on RecentChanges.
+
+When fixing, need to keep in mind that we can't just run the input through
+titlepage, since in all other circumstances, the page name is already valid
+and we don't want to doubly-encode it.
+
+Seems like the goto plugin needs to check if the page name is valid and
+pass it through titlepage if not.
+
+(As a side effect of this, 404 will start redirecting "http://wiki/some page
+with spaces" to "http://wiki/some_page_with_spaces", if the latter exists.
+That seems like a fairly good thing.)
+
+[[done]]
+
+--[[Joey]]
--- /dev/null
+Some elements of
+[HTML5](http://www.whatwg.org/specs/web-apps/current-work/multipage/) can be
+safely supported by ikiwiki. There are [several differences between HTML4 and
+HTML5](http://www.w3.org/TR/html5-diff/).
+
+[[!template id=gitbranch branch=hendry/html5 author="[[Kai_Hendry|hendry]]"]]
+
+* [HTML5 branch](http://git.webconverger.org/?p=ikiwiki;h=refs/heads/html5)
+* [ikiwiki instance with HTML5 templates](http://natalian.org)
+* [HTML5 outliner tool](http://gsnedders.html5.org/outliner/) -- to check you have the structure of your markup correct
+
+# htmlscrubber.pm needs to not scrub new HTML5 elements
+
+* [new elements](http://www.w3.org/TR/html5-diff/#new-elements)
+
+# HTML5 Validation and t/html.t
+
+[validator.nu](http://validator.nu/) is the authorative HTML5 validator,
+however it is almost impossible to sanely introduce as a build dependency
+because of its insane Java requirements. :( I test locally via
+[cURL](http://wiki.whatwg.org/wiki/IDE), though Debian packages cannot be built
+with a network dependency.
+
+In the future, hopefully ikiwiki can test for valid HTML5 using [Relax NG
+schema](http://syntax.whattf.org/) using a Debian package tool
+[rnv](http://packages.qa.debian.org/r/rnv.html).
+
+# HTML5 migration issues
+
+# [article](http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#the-article-element) element
+
+This element is poorly supported by browsers. As a workaround, `style.css` needs:
+
+ article {
+ display: block;
+ }
+
+Internet Explorer will display it as a block, though you can't seem to be able to further control the style.
+
+## Time element
+
+The [time element](http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-time-element) ideally needs the datatime= attribute set by a template variable with what [HTML5 defines as a valid datetime string](http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#valid-global-date-and-time-string).
+
+As a workaround:
+
+ au:~% grep timeformat natalian.setup
+ timeformat => '%Y-%m-%d',
ikiwiki will generate html formatted error messages to the command
line if --cgi is set, even if it's not yet running as a cgi
+
+> [[done]], at last. Oldest open bug.. just thought of an elegant fix!
+> --[[Joey]]
--- /dev/null
+From the source of [[usage]]:
+
+ <a href="mailto:joey@ikiwiki.info">joey@ikiwiki.info</a>
+
+Text::Markdown obfuscates email addresses in the href= attribute and in the text.
+Apparently this can't be configured.
+
+HTML::Scrubber doesn't set `attr_encoded` for its HTML::Parser, so the href= attribtute is decoded.
+Currently it seems it doesn't set `attr_encoded` for good reason: so attributes can be sanitized easily,
+e.g. as in htmlscrubber with `$safe_url_regexp`.
+This apparently can't be configured either.
+
+So I can't see an obvious solution to this.
+Perhaps improvements to Text::Markdown or HTML::Scrubber can allow a fix.
+
+One question is: how useful is email obfuscation?
+Don't spammers use HTML parsers?
+
+> I now see this was noted in the formatting [[/ikiwiki/formatting/discussion]], and won't/can't be fixed.
+> So I guess this is [[done]]. --Gabriel
+
+I've [[patch]]ed mdwn.pm to prevent Text::Markdown from obfuscating the emails.
+The relevant commits are on the master branch of [my "fork" of ikiwiki on Github] [github]:
+
+- 7d0970adbcf0b63e7e5532c239156f6967d10158
+- 52c241e723ced4d7c6a702dd08cda37feee75531
+
+--Gabriel.
+
+[github]: http://github.com/gmcmanus/ikiwiki/
+
+> Thanks for coming up with a patch, but overriding
+> `Text::Markdown::_EncodeEmailAddress` gets into its internals more than
+> I'm comfortable with.
+>
+> It would probably be best to add an option to [[!cpan Text::Markdown]] to
+> let the email address munging be disabled. --[[Joey]]
> to be no way to override it reading /etc/tidy.conf, so options there can
> still screw things up. I guess I'll pass --markup yes and deal with
> overriding other problem settings from config files if they're found
-> later. --[[Joey]] [[tag done]]
+> later. --[[Joey]] [[!tag done]]
newenviron[i++]="HTTPS_PROXY=http://host.domain.com:3128";
-to IkiWiki/Wrapper.pm it solves the problem for https requests, however it obviously would be preferred if the proxy name is not configured.
+to IkiWiki/Wrapper.pm it solves the problem for https requests, however it obviously would be preferred if the proxy name is not hard coded.
Also, the ability to set HTTPS\_CA\_FILE and HTTPS\_CA\_DIR might benefit some people. Then again, it I can't see any evidence that the SSL certificate of the server is being checked. See the [[bug_report|ssl_certificates_not_checked_with_openid]] I filed on this separate issue.
Unfortunately, HTTP\_PROXY doesn't work for http requests, it looks like that library is different.
+---
+
+Update 2008-10-26:
+
+Better solution, one that works for both http and https, and uses config options. It appears to work...
+
+Note that using $ua->proxy(['https'], ...); won't work, you get a "Not Implemented" error, see <http://community.activestate.com/forum-topic/lwp-https-requests-proxy>. Also see [[!debbug 129528]].
+
+Also note that the proxy won't work with liblwpx-paranoidagent-perl, I had to remove liblwpx-paranoidagent-perl first.
+
+Please get the patch from the *.mdwn source.
+
+louie:/usr/share/perl5/IkiWiki/Plugin# diff -u openid.pm.old openid.pm
+--- openid.pm.old 2008-10-26 12:18:58.094489360 +1100
++++ openid.pm 2008-10-26 12:40:05.763429880 +1100
+@@ -165,6 +165,14 @@
+ $ua=LWP::UserAgent->new;
+ }
+
++ if (defined($config{"http_proxy"})) {
++ $ua->proxy(['http'], $config{"http_proxy"});
++ }
++
++ if (defined($config{"https_proxy"})) {
++ $ENV{HTTPS_PROXY} = $config{"https_proxy"};
++ }
++
+ # Store the secret in the session.
+ my $secret=$session->param("openid_secret");
+ if (! defined $secret) {
+
+
Brian May
+++ /dev/null
-A lot of strings in ikiwiki are hardcoded and not taken for locales resources through gettext. This is bad because ikiwiki is thus difficult to spread for non-english users.
-
-I mean that, for instance in CGI.pm, line like:
-
-`my @buttons=("Save Page", "Preview", "Cancel");`
-
-should be written as
-
-`my @buttons=(gettext("Save Page"), gettext("Preview"), gettext("Cancel"));`
-
-> Yes, these need to be fixed. But note that the localised texts come back
-> into ikiwiki and are used in various places, including plugins.
-> Including, possibly, third-party plugins. So localising the buttons would
-> seem to require converting from the translations back into the C locale
-> when the form is posted. --[[Joey]]
-
-In standards templates things seems wrongly written too. For instance in page.tmpl line like:
-
-`<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>`
-
-should be written as
-
-`<li><a href="<TMPL_VAR EDITURL>" rel="nofollow"><TMPL_VAR EDITURL_TEXT</a></li>`
-
-with EDITURL_TEXT variable initialized in Render.pm through a gettext call.
-
-Am I wrong ?
-
-> No, that's not a sane way to localise the templates. The templates can be
-> translated by making a copy and modifying it, or by using a tool to
-> generate .mo files from the templates, and generate translated templates
-> from .po files. (See [[todo/l10n]] for one attempt.) But pushing the
-> localisation of random strings in the templates through the ikiwiki
-> program defeats the purpose of having templates at all. --[[Joey]]
-
-If not I can spend some time preparing patches for such corrections if it can help.
-
--- [[/users/bbb]]
--- /dev/null
+I can make an image link, such as:
+
+ 
+
+That will render as .
+
+If I then inline that page, the (relative) URL no longer points to the right place. The fix for this promises to be hairy.
+
+> Similarly, if you insert a relative link using the markdown link syntax,
+> it will tend to break when the page is inlined.
+>
+> However, there is a simple way to avoid both problems: Use WikiLinks
+> and/or the [[img_directive|ikiwiki/directive/img]]. --[[Joey]]
+
+[[!tag done]]
The img plugin causes a taint failure if one tries to link a scaled image, e.g.
- \[[img foo.png size=64x64]]
+ \[[!img foo.png size=64x64]]
.ikiwiki.setup: Insecure dependency in mkdir while running with -T switch at /usr/lib/perl5/vendor_perl/5.8.8/IkiWiki.pm line 360.
BEGIN failed--compilation aborted at (eval 5) line 109.
**Update**: this is the same bug as [[the_colon-in-links_bug|No_link_for_blog_items_when_filename_contains_a_colon]]
-[[tag done]]
+[[!tag done]]
index 7226231..3eb1ae7 100644
--- a/Plugin/img.pm
+++ b/Plugin/img.pm
- @@ -93,9 +93,15 @@ sub preprocess (@) { #{{{
+ @@ -93,9 +93,15 @@ sub preprocess (@) {
$imgurl="$config{url}/$imglink";
}
+ $result .= '/></a>';
+
+ return $result;
- } #}}}
+ }
1
--
--- /dev/null
+The [[ikiwiki/directive/img]] directive emits an extra double quote if alt=x is
+specified (as is necessary for valid HTML). This results in malformed HTML,
+like this:
+
+ <img src="U" width="W" height="H"" alt="A" />
+ ^
+
+This [[patch]] is available from the img-bugfix branch in my git repository:
+
+ commit a648c439f3467571374daf597e9b3a659ea2008f
+ Author: Simon McVittie <smcv@ http://smcv.pseudorandom.co.uk/>
+ Date: 2009-06-16 17:15:06 +0100
+
+ img plugin: do not emit a redundant double-quote before alt attribute
+
+ diff --git a/IkiWiki/Plugin/img.pm b/IkiWiki/Plugin/img.pm
+ index a697fea..a186abd 100644
+ --- a/IkiWiki/Plugin/img.pm
+ +++ b/IkiWiki/Plugin/img.pm
+ @@ -121,7 +121,7 @@ sub preprocess (@) {
+ my $imgtag='<img src="'.$imgurl.
+ '" width="'.$im->Get("width").
+ '" height="'.$im->Get("height").'"'.
+ - (exists $params{alt} ? '" alt="'.$params{alt}.'"' : '').
+ + (exists $params{alt} ? ' alt="'.$params{alt}.'"' : '').
+ (exists $params{title} ? ' title="'.$params{title}.'"' : '').
+ (exists $params{class} ? ' class="'.$params{class}.'"' : '').
+ (exists $params{id} ? ' id="'.$params{id}.'"' : '').
+
+--[[smcv]]
+
+[[done]] --[[Joey]]
> said broken software will then display its old out of date cached
> version.
>
-> So, not changing this. [[tag done]]
+> So, not changing this. [[!tag done]]
>
> --[[Joey]]
--- /dev/null
+When you do various CGI actions, "index.html" is visible in the redirection URL. It's desirable that this is avoided, so there is only one visible URL for each page (search engines don't think that /foo/index.html is equivalent to /foo/, since this is not necessarily true for all servers and configurations).
+
+[The beautify branch in my repository](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=shortlog;h=refs/heads/beautify) contains [[patches|patch]] for all the cases I found by grepping for "htmlpage", which are:
+
+* [[plugins/editpage]] redirects you to the page under various circumstances, most visibly after you finish editing it
+* [[plugins/poll]] redirects you to the poll after voting
+* [[plugins/recentchanges]] redirects you to the relevant page when you click a link
+* [[plugins/remove]] redirects you to the parent of the removed page
+
+I think the coding standard in future should be: use htmlpage when you want a local file, or urlto if you want a URL.
+
+> Agreed, and I've updated the docs accordingly. Merged your changes. BTW,
+> did you notice they included a fix in passing for a bug in the recentchanges
+> redirection? [[done]] --[[Joey]]
+
+>> No, I suppose I must have assumed htmlpage already did the pagetype check... --[[smcv]]
Hi, I try to make an example to reproduce some bug with inline and toc plugins.
My friend uses
- \[[inline pages="users/joey" raw="yes"]]
+ \[[!inline pages="users/joey" raw="yes"]]
to include common snippets in various pages, and it works as advertised, but if toc plugin is used, page is messed up.
> [here](http://bugs.debian.org/421843).
>
> I'm going to close this bug report since it's a markdown bug. --[[Joey]]
-[[tag done]]
+[[!tag done]]
>> thanks, that fixes it.
* bl bla
* aadsd
-[[toc levels=2]]
+[[!toc levels=2]]
bla bla
-[[table data="""
+[[!table data="""
Customer|Amount
Fulanito|134,34
Menganito|234,56
Here's a paragraph.
-[[inline pages="users/joey" raw="yes"]]
+[[!inline pages="users/joey" raw="yes"]]
bla bla
--- /dev/null
+If I put something like the below in my index.mdwn
+
+ <<!inline pages="posts/* and !*/discussion" rootpage="posts" show="10">>
+
+But posts doesn't exist, I get the following in index.html
+
+ <input type="hidden" name="do" value="blog" />
+ <input type="hidden" name="from" value="" />
+ <input type="hidden" name="subpage" value="1" />
+
+When I create posts (touch posts.mdwn), I get the following in index.html
+
+ <input type="hidden" name="do" value="blog" />
+ <input type="hidden" name="from" value="posts" />
+ <input type="hidden" name="subpage" value="1" />
+
+Bug?
+
+> Yes, thanks for reminding me I need to do something about that... [[done]]
+> --[[Joey]]
> filesystem. It just avoids you having to get the case right when
> referring to existing files, by wikilinks or pagespecs --[[Joey]]
-[[tag done]]
+[[!tag done]]
--- /dev/null
+The [[plugins/inline]] plugin has a `sort="title"` option that causes the pages in the list to be sorted by title rather than creation time. The [[plugins]] list on this wiki was recently changed to use this option. If you look at the plugin page, you'll notice that it doesn't look correctly sorted. e.g. `attach (third party plugin)` falls between `conditional` and `default content for *copyright* and *license*`.
+
+I think the problem here is that the pages are being sorted by their path, whereas only the basename is displayed. This makes the example above:
+
+ * plugins/conditional
+ * plugins/contrib/attach
+ * plugins/contrib/default content for *copyright* and *license*
+
+and now you can see why it is ordered that way, and why later on we get:
+
+ * plugins/contrib/unixauth (third party plugin)
+ * plugins/creole
+
+which appears to list `unixauth` before `creole`.
+
+I'm not sure what the best fix is. One fix would be to add another sort option, `sort="path"`, that would use the current (broken) sort by title. Then add a true `sort="title"` that actually sorts on the title. It might also be interesting to modify the sort=path to actually list the full path in the links - that way it would be obvious how it is sorted. Or you could ignore the idea for `sort="path"`, and tell people to use [[plugins/map]] for that.
+
+--[[users/Will]]
+
+And here is a [[patch]] for this. It makes `sort=title` actually sort on the title, and adds `sort=path` if you really want to sort on the path. `sort=path` still only displays titles. Just use map if you want more.
+
+ diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm
+ index 9c336e7..99f6de3 100644
+ --- a/IkiWiki/Plugin/inline.pm
+ +++ b/IkiWiki/Plugin/inline.pm
+ @@ -185,9 +185,12 @@ sub preprocess_inline (@) {
+ }
+ }
+
+ - if (exists $params{sort} && $params{sort} eq 'title') {
+ + if (exists $params{sort} && $params{sort} eq 'path') {
+ @list=sort @list;
+ }
+ + elsif (exists $params{sort} && $params{sort} eq 'title') {
+ + @list=sort { lc(pagetitle(basename($a))) cmp lc(pagetitle(basename($b))) } @list;
+ + }
+ elsif (exists $params{sort} && $params{sort} eq 'mtime') {
+ @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list;
+ }
+ diff --git a/doc/ikiwiki/blog.mdwn b/doc/ikiwiki/blog.mdwn
+ index 19ec7ac..7608628 100644
+ --- a/doc/ikiwiki/blog.mdwn
+ +++ b/doc/ikiwiki/blog.mdwn
+ @@ -89,7 +89,8 @@ Here are some less often needed parameters:
+ inlining page.
+ * `sort` - Controls how inlined pages are sorted. The default, "age" is to
+ sort newest created pages first. Setting it to "title" will sort pages by
+ - title, and "mtime" sorts most recently modified pages first.
+ + title, "path" sorts by the path to the page, and "mtime" sorts most
+ + recently modified pages first.
+ * `reverse` - If set to "yes", causes the sort order to be reversed.
+ * `feedshow` - Specify the maximum number of matching pages to include in
+ the rss/atom feeds. The default is the same as the `show` value above.
+
+> Thanks for the patch. [[done]], but I left off the sort=path. Also left
+> off the lc (if you ask your locale to sort case-sensatively, it should, I
+> think). --[[Joey]]
--- /dev/null
+I have a directory containing two files. f1 (<http://alcopop.org/~jon/repro2/src/blog/debgtd.html>) has
+
+ meta date="2008-07-02 14:13:17"
+
+f2 (<http://alcopop.org/~jon/repro2/src/blog/moving.html>) has
+
+ meta date="2008-07-02 21:04:21"
+
+They have both been modified recently:
+
+ >>> stat(f1)
+ (33188, 459250L, 65027L, 1, 1000, 1000, 1686L, 1227967177, 1227966706, 1227966706)
+ >>> stat(f2)
+ (33188, 458868L, 65027L, 1, 1000, 1000, 938L, 1227967187, 1227966705, 1227966705)
+
+Note that f1 is fractionally newer than f2 in terms of ctime and mtime, but f2 is much newer in terms of the meta information.
+
+Another page includes them both via inline:
+
+ inline pages="blog/*" show=5
+
+The resulting page is rendered with f1 above f2, seemingly not using the meta directive information: <http://alcopop.org/~jon/repro2/dest/blog/>. The footer in the inline pages does use the correct time e.g. <em>Posted Wed 02 Jul 2008 14:13:17 BST</em>.
+
+If I instead include them using creation_year in the pagespec, they are ordered correctly.
+
+<http://alcopop.org/~jon/repro2/> contains the src used to reproduce this, the precise ikiwiki invocation (inside Makefile) and the results (dest).
+
+-- [[users/Jon]]
+
+
+> On Ikiwiki 2.53.3 (Debian Lenny), my inlines are also sorted using mtime
+> by default -- despite what the [[documentation|/ikiwiki/directive/inline]]
+> says -- but setting the supposed default sort order manually produces the
+> correct results. For example, the following inline sorts my blog
+> entires using their meta date or ctime:
+>
+> inline pages="blog/*" show="10" sort="age"
+>
+> I'll try to look at the code this weekend and see if age is really the
+> default sort order.
+>
+> -- [David A. Harding](http://dtrt.org), 2008-12-20
+
+Here is the code. As you can see, sort="age" is equivilant to leaving
+out the sort option. --[[Joey]]
+
+ if (exists $params{sort} && $params{sort} eq 'title') {
+ @list=sort { pagetitle(basename($a)) cmp pagetitle(basename($b)) } @list;
+ }
+ elsif (exists $params{sort} && $params{sort} eq 'mtime') {
+ @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list;
+ }
+ elsif (! exists $params{sort} || $params{sort} eq 'age') {
+ @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
+ }
+ else {
+ return sprintf(gettext("unknown sort type %s"), $params{sort});
+ }
+
+> On further testing, I find that the bug is limited to the first time
+> creation time should be used and has nothing to do with setting the sort
+> parameter. Revised steps to reproduce: --[David A. Harding](http://dtrt.org), 2008-12-20
+>
+> 1. Create pages that sort different by mtime and ctime
+>
+> 2. inline pages="somepages/*"
+>
+> 3. ikiwiki --setup setup_file
+>
+> 4. Pages are output incorrectly in mtime order
+>
+> 5. ikiwiki --setup setup_file
+>
+> 6. Pages are output correctly in ctime order
+>
+> 7. Create new page in somepages/, set its ctime to earlier than another
+> page in sompages/
+>
+> 8. ikiwiki --setup setup_file
+>
+> 9. All previously sorted pages output correctly in ctime order but new
+> page is output incorrectly at the top as if its mtime was its ctime
+>
+> 10. ikiwiki --setup setup_file
+>
+> 11. All pages, including new page, are output correctly in ctime order
+
+You're confusing ctime and creation time. This is perhaps not suprising, as
+ikiwiki uses the term 'ctime' to refer to creation time. However, the unix
+ctime value is not the same thing. Unix ctime can change if a file changes
+owner, or in some cases, permissions. Unix ctime also always changes
+when the file is modified. Ikiwiki wants a first creation date of the file,
+and it accomplishes this by recording the initial ctime of a file the first
+time it processes it, and *preserving* that creation time forever, ignoring
+later ctime changes.
+
+I suspect that this, coupled with the fact that ikiwiki sorts newest pages
+first, explains everything you describe. If not, please send me a shell script
+test case I can run, as instructions like "Create pages that sort different by
+mtime and ctime" are not ones that I know how to follow (given that touch sets
+*both*). --[[Joey]]
+
+> Sorry. I conflated Unix ctime and ikiwiki's creation time because I
+> didn't think the difference was important to this case. I'm a writer,
+> and I should have known better -- I appologize. Revised steps to
+> reproduce are below; feel free to delete this whole misunderstanding
+> to make the bug report more concise.
+>
+> 1. Create pages in the srcdir that should sort in one order by
+> last-modification time and in a diffent order by original creation
+> time. For example:
+>
+> $ echo -e '\[[!meta date="2007-01-01"]]\nNew.' > test/new.mdwn
+> $ echo -e '\[[!meta date="2006-01-01"]]\nOld.' > test/old.mdwn
+>
+> 2. Create a page that includes the files. For example:
+>
+>
+> $ echo '\[[!inline pages="test/*"]]' > sort-test.mdwn
+>
+> 3. Run ikiwiki. For example `ikiwiki --setup setup_file`
+>
+> 4. Pages are output incorrectly in modification time order. For example,
+> actual partial HTML of the sort-test/index.html from commands used
+> above (whitespace-only lines removed; one whitespace-only line
+> added):
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/old/">old</a>
+> </span>
+> <p>Old.</p>
+> <span class="pagedate">
+> Posted Sun 01 Jan 2006 12:00:00 AM EST
+> </span>
+> </div>
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/new/">new</a>
+> </span>
+> <p>New.</p>
+> <span class="pagedate">
+> Posted Mon 01 Jan 2007 12:00:00 AM EST
+> </span>
+> </div>
+>
+> 5. Run ikiwiki again with the same command line. For example: `ikiwiki --setup setup_file`
+>
+> 6. Pages are output correctly in creation time order. For example,
+> actual partial HTML of the sort-test/index.html from commands used
+> above (whitespace-only lines removed; one whitespace-only line
+> added):
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/new/">new</a>
+> </span>
+> <p>New.</p>
+> <span class="pagedate">
+> Posted Mon 01 Jan 2007 12:00:00 AM EST
+> </span>
+> </div>
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/old/">old</a>
+> </span>
+> <p>Old.</p>
+> <span class="pagedate">
+> Posted Sun 01 Jan 2006 12:00:00 AM EST
+> </span>
+> </div>
+>
+> 7. Create a new page with the current Unix mtime and Unix ctime, but a
+> !meta date before the most recent creation date of another page.
+> For example:
+>
+> $ echo -e '\[[!meta date="2005-01-01"]]\nOlder.' > test/older.mdwn
+>
+> 8. Run ikiwiki again with the same command line. For example: `ikiwiki --setup setup_file`
+>
+> 9. All previously sorted pages output correctly in order of their
+> creation time, but the new page is output incorrectly at the top as
+> if its modification time was its creation time. For example,
+> actual partial HTML of the sort-test/index.html from commands used
+> above (whitespace-only lines removed; two whitespace-only
+> lines added):
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/older/">older</a>
+> </span>
+> <p>Older.</p>
+> <span class="pagedate">
+> Posted Sat 01 Jan 2005 12:00:00 AM EST
+> </span>
+> </div>
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/new/">new</a>
+> </span>
+> <p>New.</p>
+> <span class="pagedate">
+> Posted Mon 01 Jan 2007 12:00:00 AM EST
+> </span>
+> </div>
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/old/">old</a>
+> </span>
+> <p>Old.</p>
+> <span class="pagedate">
+> Posted Sun 01 Jan 2006 12:00:00 AM EST
+> </span>
+> </div>
+>
+> 10. Run ikiwiki again with the same command line. For example: `ikiwiki --setup setup_file`
+>
+> 11. All pages, including new page, are output correctly in creation time
+> order. For example, actual partial HTML of the sort-test/index.html
+> from commands used above (whitespace-only lines removed; two
+> whitespace-only lines added):
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/new/">new</a>
+> </span>
+> <p>New.</p>
+> <span class="pagedate">
+> Posted Mon 01 Jan 2007 12:00:00 AM EST
+> </span>
+> </div>
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/old/">old</a>
+> </span>
+> <p>Old.</p>
+> <span class="pagedate">
+> Posted Sun 01 Jan 2006 12:00:00 AM EST
+> </span>
+> </div>
+>
+> <div class="inlinepage">
+> <span class="header">
+> <a href="./../test/older/">older</a>
+> </span>
+> <p>Older.</p>
+> <span class="pagedate">
+> Posted Sat 01 Jan 2005 12:00:00 AM EST
+> </span>
+> </div>
+>
+> File status after all the above actions:
+>
+> $ stat test/*
+> File: `test/new.mdwn'
+> Size: 33 Blocks: 8 IO Block: 4096 regular file
+> Device: ca20h/51744d Inode: 684160 Links: 1
+> Access: (0644/-rw-r--r--) Uid: ( 1000/ harding) Gid: ( 1000/ harding)
+> Access: 2008-12-20 21:48:32.000000000 -0500
+> Modify: 2008-12-20 21:27:03.000000000 -0500
+> Change: 2008-12-20 21:27:03.000000000 -0500
+> File: `test/older.mdwn'
+> Size: 35 Blocks: 8 IO Block: 4096 regular file
+> Device: ca20h/51744d Inode: 684407 Links: 1
+> Access: (0644/-rw-r--r--) Uid: ( 1000/ harding) Gid: ( 1000/ harding)
+> Access: 2008-12-20 21:48:32.000000000 -0500
+> Modify: 2008-12-20 21:42:10.000000000 -0500
+> Change: 2008-12-20 21:42:10.000000000 -0500
+> File: `test/old.mdwn'
+> Size: 33 Blocks: 8 IO Block: 4096 regular file
+> Device: ca20h/51744d Inode: 684161 Links: 1
+> Access: (0644/-rw-r--r--) Uid: ( 1000/ harding) Gid: ( 1000/ harding)
+> Access: 2008-12-20 21:48:32.000000000 -0500
+> Modify: 2008-12-20 21:27:09.000000000 -0500
+> Change: 2008-12-20 21:27:09.000000000 -0500
+>
+> My ikiwiki configuration file (being used to port a blog from pyblosxom
+> to ikiwiki):
+>
+> harding@mail:~$ sed 's/#.*//; /^[ ]*$/d' .ikiwiki/gnuisance.setup
+> use IkiWiki::Setup::Standard {
+> wikiname => "HardingBlog",
+> adminemail => 'dave@dtrt.org',
+> srcdir => "/srv/backup/git/gnuisance.net",
+> destdir => "/srv/test.dtrt.org",
+> url => "http://srv.dtrt.org",
+> wrappers => [
+> ],
+> atom => 1,
+> syslog => 0,
+> prefix_directives => 1,
+> add_plugins => [qw{goodstuff tag}],
+> disable_plugins => [qw{passwordauth}],
+> tagbase => "tag",
+> }
+>
+> --[David A. Harding](http://dtrt.org/), 2008-12-20
+
+Thank you for a textbook excellent reproduction recipe.
+
+What appears to be going on here is that meta directives are not processed
+until the leaf pages are rendered, and thus the ctime setting is not
+available at the time that they are inlined, and the newer unix ctime is
+used. On the second build, the meta data has already been recorded.
+
+This can probably be avoided by processing meta date at scan time.
+
+Verified, fix works. [[done]]
+--[[Joey]]
--- /dev/null
+dunno if it just me, but I had to add PREFIX a few places to get 'perl INSTALL_BASE=$HOME' to work
+
+> That will cause the files to be installed into a place that ikiwiki
+> doesn't look for them. It will also cause them to be installed into
+> /usr/etc by default, where ikiwiki also won't find them.
+>
+> Thomas Keller also ran into some sort of problem with the MacPort
+> involving the installation into /etc. From that discussion:
+>
+> Both ikiwiki-update-wikilist and ikiwiki-mass-rebuild hardcode /etc; so
+> do several pages in the doc wiki.
+>
+> The real problem though is that MakeMaker does not have a standard way
+> of specifying where /etc files go. In Debian we want everything to go
+> into /usr, rather than the default /usr/local, so set PREFIX=/usr -- but
+> we still want config files in /etc, not /usr/etc. The only way I can see
+> around this is to add a nonstandard variable to control the location of
+> /etc, that would override the PREFIX.
+>
+> Which implies that you can't just use "$installdir/etc/" in the /etc
+> hardcoding scripts, and would instead need to record the new variable
+> at build time, like PREFIX is recorded in $installdir.
+>
+> Instead, let's ignore failure of the lines. [[done]]
+>
+> --[[Joey]]
+
+<pre>
+From a1e02fbdaba3725730418a837b506e713904ada5 Mon Sep 17 00:00:00 2001
+From: David Bremner <bremner@pivot.cs.unb.ca>
+Date: Fri, 29 Aug 2008 15:18:24 -0300
+Subject: [PATCH] add missing $(PREFIX) to install path
+
+---
+ Makefile.PL | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/Makefile.PL b/Makefile.PL
+index 979483c..1f27394 100755
+--- a/Makefile.PL
++++ b/Makefile.PL
+@@ -50,9 +50,9 @@ extra_clean:
+ $(MAKE) -C po clean
+
+ extra_install:
+- install -d $(DESTDIR)/etc/ikiwiki
+- install -m 0644 wikilist $(DESTDIR)/etc/ikiwiki
+- install -m 0644 auto.setup $(DESTDIR)/etc/ikiwiki
++ install -d $(DESTDIR)$(PREFIX)/etc/ikiwiki
++ install -m 0644 wikilist $(DESTDIR)$(PREFIX)/etc/ikiwiki
++ install -m 0644 auto.setup $(DESTDIR)$(PREFIX)/etc/ikiwiki
+
+ install -d $(DESTDIR)$(PREFIX)/share/ikiwiki
+ for dir in `cd underlays && find . -follow -type d ! -regex '.*\.svn.*'`; do \
+--
+1.5.6.3
+</pre>
--- /dev/null
+If a link inside a CSV file contains two or more underscores (\_), then it will get mis-parsed by the table plugin.
+
+e.g. \[[single\_track\_lines]] becomes "em>lines".
+
+Links with only one underscore are OK.
+
+Update 2008-11-24: The problem only occurs if the CSV data is in an external file. If I load it using data="""...""" then it works fine.
+
+The problem appears to be the call to htmlize inside genrow. If the data is inline, then wikilinks get expanded before they get here, and are OK. If the data is from an external file, the wikilinks aren't expanded, and htmlize will expand \[[single\_track\_lines]] into \[[single<em>track</em>lines]].
+
+Oh, wait, I see the problem. IkiWiki::linkify is only called if the external file doesn't exist. If I remove this check and always call IkiWiki::linkify, then the problem is solved.
+
+(this is inside /usr/share/perl5/IkiWiki/Plugin/table.pm).
+
+> To reproduce this bug, I had to install the old, broken markdown 1.0,
+> instead of the now-default Text::Markdown.
+>
+> Why is linkify not called for external files? Well, I checked the
+> history, and it's probably best to say "for historical reasons that no
+> longer apply". So, changed as you suggest. [[done]] --[[Joey]]
+
+I am rather confused what this check does, and the fact the comments are very different for CSV and DSV when the code is the same doesn't seem to help.
+
+> The code is not the same; two operations are run in different orders for
+> CSV and DSV, as the comments note. --[[Joey]]
+
+-- Brian May
-[[plugins/lockedit]] adds the form fields for a [[pagespec]] to preferences. This pagespec should be supplied "raw"; i.e., without quotes around it. Inexperienced users (such as [[myself|jondowland]]) may provide an invalid pagespec, such as one with quotes on it. This will be merrily accepted by the form, but will cause no locking to take place.
+[[plugins/lockedit]] adds the form fields for a [[pagespec]] to preferences. This pagespec should be supplied "raw"; i.e., without quotes around it. Inexperienced users (such as [[myself|users/jon]]) may provide an invalid pagespec, such as one with quotes on it. This will be merrily accepted by the form, but will cause no locking to take place.
Perhaps some validation should be performed on the pagespec and the form-submission return include "warning: this pagespec is invalid" or "warning: this pagespec does not match any existing pages" or similar.
+
+> The pagespec is no longer in the preferences and instead in the setup
+> file now. That makes warning about a problem with it harder.
+>
+> Ikiwiki could try to detect this problem and warn at setup time to
+> stderr, I guess.
+>
+> Main problem is I see little way to actually detect the problem you
+> described. A pagespec with quotes around it is valid. For example, the
+> pagespec `"foo or bar"` matches a page named `"foo` or a page named `bar"`.
+>
+> There are small classes of invalid pagespecs. For example, `(foo or bar`
+> is invalid due to having unbalanced parens, while `foo or and bar`
+> has invalid syntax. It's possible to detect these, I guess ... --[[Joey]]
+
+>> Having moved it to the .setup file makes things more obvious I think.
+>> Anyway I consider this [[done]], please de-done this if you disagree.
+>> --[[Jon]]
--- /dev/null
+At the moment, you go through the login shuffle and then are told that cookies are needed, so you lose all your data and login again. It would be much slicker to note by the edit link, or at least on the login page, that cookies are required.
+
+> Hmm, it seems to me to be fairly obvious, since the vast majority of
+> websites that have a login require cookies. Such warnings used to be
+> common, but few sites bother with them anymore. --[[Joey]]
+
+>> Very few websites break without cookies. Even fewer lose data.
+>> Can ikiwiki avoid being below average by default? --[MJR](http://mjr.towers.org.uk)
+
+>>> Can we avoid engaging in hyperbole? (Hint: Your browser probably has a
+>>> back button. Hint 2: A username/password does not count as "lost data".
+>>> Hint 3: Now we're arguing, which is pointless.) --[[Joey]]
+
+Even better would be to only display the cookie note as a warning if the login page doesn't receive a session cookie.
+
+> I considered doing this before, but it would require running the cgi once
+> to attempt to set the cookie and then redirecting to the cgi a second
+> time to check if it took, which is both complicated and probably would
+> look bad.
+
+>> Might this be possible client-side with javascript? A quick google suggests it is possible:
+>> <http://www.javascriptkit.com/javatutors/cookiedetect.shtml>. MJR, want to try adding
+>> that? -- [[Will]]
+
+Best of all would be to use URL-based or hidden-field-based session tokens if cookies are not permitted.
+
+> This is not very doable since most of the pages the user browses are
+> static pages in a static location.
+
+>> The pages that lose data without cookies (the edit pages, primarily)
+>> don't look static. Are they really? --[MJR](http://mjr.towers.org.uk)
+
+>>> As soon as you post an edit page, you are back to a static website.
-[[meta title="mailto: links not properly generated in rss/atom feeds"]]
+[[!meta title="mailto: links not properly generated in rss/atom feeds"]]
A link like \[this](mailto:foo@bar.org) will not be converted correctly to a mailto link in the rss/atom feeds, but an absolute link instead. See e.g. the logitech post on http://madduck.net/blog/feeds/planet-lca2008/index.rss
-> fixed --[[Joey]] [[tag done]]
+> fixed --[[Joey]] [[!tag done]]
-[[meta title="map does not link entries which are equal to basename(current_page)"]]
+[[!meta title="map does not link entries which are equal to basename(current_page)"]]
On <http://phd.martin-krafft.net/wiki/tag/factors/>, the top-level `factors` entry is not linked to the corresponding page. Looking at <http://phd.martin-krafft.net/wiki/tag/factors/language/>, this must be because the page name is the same as the entry name, and ikiwiki probably doesn't take the complete path of subpages into account.
## given map:
-\[[map pages="blog/tags/*"]]
+\[[!map pages="blog/tags/*"]]
## received map:
--- /dev/null
+[[!tag plugins/map patch]]
+
+input:
+
+ before.
+ \[[!map pages="sdfsdfsdfsd/*"]]
+ after.
+
+Presuming that the pagespec does not match, output:
+
+ <p>before.
+ <div class="map">
+ <ul>
+ </div></p>
+
+The UL element is not closed.
+
+Patch:
+
+ --- /usr/share/perl5/IkiWiki/Plugin/map.pm 2009-05-06 00:56:55.000000000 +0100
+ +++ IkiWiki/Plugin/map.pm 2009-06-15 12:23:54.000000000 +0100
+ @@ -137,11 +137,11 @@
+ $openli=1;
+ $parent=$item;
+ }
+ - while ($indent > 0) {
+ + while ($indent > 1) {
+ $indent--;
+ $map .= "</li>\n</ul>\n";
+ }
+ - $map .= "</div>\n";
+ + $map .= "</ul>\n</div>\n";
+ return $map;
+ }
+
+
+-- [[Jon]]
+
+> Strictly speaking, a `<ul>` with no `<li>`s isn't valid HTML either...
+> could `map` instead delay emitting the first `<ul>` until it determines that
+> it will have at least one item? Perhaps refactoring that function into
+> something easier to regression-test would be useful. --[[smcv]]
+
+>> You are right (just checked 4.01 DTD to confirm). I suspect refactoring
+>> the function would be wise. From my brief look at it to formulate the
+>> above I thought it was a bit icky. I'm not a good judge of what would
+>> be regression-test friendly but I might have a go at reworking it. With
+>> this variety of problem I have a strong inclination to use HOFs like map,
+>> grep. - [[Jon]]
+
+>>> The patch in [[map/discussion|plugins/map/discussion]] has the same
+>>> problem, but does suggest a simpler approach to solving it (bail out
+>>> early if the map has no items at all). --[[smcv]]
+
+>>>> Thanks for pointing out the problem. I guess this patch should solve it.
+>>>> --[[harishcm]]
+
+>>>>> Well, I suppose that's certainly a minimal patch for this bug :-)
+>>>>> I'm not the IkiWiki maintainer, but if I was, I'd apply it, so I've put
+>>>>> it in a git branch for Joey's convenience. Joey, Jon: any opinion?
+>>>>>
+>>>>> If you want to be credited for this patch under a name other than
+>>>>> "harishcm" (e.g. your real name), let me know and I'll amend the branch.
+>>>>> (Or, make a git branch of your own and replace the reference just below,
+>>>>> if you prefer.) --[[smcv]]
+
+>>>>>> The current arrangement looks fine to me. Thanks. --[[harishcm]]
+
+[[!template id=gitbranch author="[[harishcm]]" branch=smcv/ready/harishcm-map-fix]]
+
+> [[merged|done]] --[[Joey]]
+
+Patch:
+
+ --- /usr/local/share/perl/5.8.8/IkiWiki/Plugin/map.pm
+ +++ map.pm
+ @@ -80,7 +80,17 @@
+ my $indent=0;
+ my $openli=0;
+ my $addparent="";
+ - my $map = "<div class='map'>\n<ul>\n";
+ + my $map = "<div class='map'>\n";
+ +
+ + # Return empty div if %mapitems is empty
+ + if (!scalar(keys %mapitems)) {
+ + $map .= "</div>\n";
+ + return $map;
+ + }
+ + else { # continue populating $map
+ + $map .= "<ul>\n";
+ + }
+ +
+ foreach my $item (sort keys %mapitems) {
+ my @linktext = (length $mapitems{$item} ? (linktext => $mapitems{$item}) : ());
+ $item=~s/^\Q$common_prefix\E\///
--- /dev/null
+The [[plugins/map]] plugin has inconsistent behaviour. In particular, I have in my wiki some directory structures holding files without wikitext pointers (I point directly to the files from elsewhere). For example, imagine the following file structure in the source dir:
+
+ ; ls -R dirA dirB
+ dirA:
+ subA subB
+
+ dirA/subA:
+ filea.mdwn fileb.mdwn
+
+ dirA/subB:
+ filec.mdwn filed.mdwn
+
+ dirB:
+ subA subC
+
+ dirB/subA:
+ filea.mdwn
+
+ dirB/subC:
+ fileb.mdwn filec.mdwn
+
+When I use map to make a map of this, the result looks more like this:
+
+<ul>
+<li><span class="createlink">? dirA</span>
+<ul>
+<li><span class="createlink">? subA</span>
+<ul>
+<li>filea
+</li>
+</ul>
+<ul>
+<li>fileb
+</li>
+</ul>
+<ul>
+<li>filec
+</li>
+<li>filed
+</li>
+</ul>
+</li>
+</ul>
+</li>
+<li><span class="createlink">? dirB</span>
+<ul>
+<li><span class="createlink">? subA</span>
+<ul>
+<li>filea
+</li>
+</ul>
+</li>
+</ul>
+<ul>
+<li><span class="createlink">? subC</span>
+<ul>
+<li>fileb
+</li>
+</ul>
+<ul>
+<li>filec
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+Note that while the dirA/subA directory exists with a create link, the dirA/subB directory is missing from the map. Interestingly, dirB/subC is shown in the map. If you add a second file to dirB/subA then dirB/subC disappears as well.
+
+I could imagine including all 'bare' directories in the map, and I could imagine including no 'bare' directories in the map. Just including the first bare directory seems a strange intermediate point.
+
+Attached is a [[patch]] that fixes the issue. The current map code makes one pass over the sorted list of pages. This adds an initial pass that goes through and makes sure that all parent directories are included. With this initial pass added, the following pass could probably be simplified.
+
+One solution could also use the [[plugins/autoindex]] plugin to make sure that parent pages actually exist. This is really only a stop-gap solution until the patch is applied - map still needs to be made bug-free.
+
+Note: This patch adds items to a map while it is in a foreach loop over a sorted list of keys from that same map. Changing a map while iterating through it is normally problematic. I'm assuming the sort insulates the code from this - I do not need to iterate over any of the newly added elements.
+
+-- [[users/Will]]
+
+> The patch is subtly buggy and just papers over the actual bug with a
+> lot of extra code. Thanks for trying to come up with a patch for this
+> annyoingly complicated bug.. I think I've fixed the underlying bug now.
+> --[[Joey]]
+>
+> [[!tag done]]
--- /dev/null
+compare:
+
+ * <jon+markdownbug@example.org>
+ * <jon.markdownbug@example.org>
+
+* <jon+markdownbug@example.org>
+* <jon.markdownbug@example.org>
+
+It seems putting a '+' in there throws it. Maybe it's a markdown bug, or maybe the obfuscation markdown applies to email-links is being caught by the HTML sanitizer.
+
+ -- [[users/Jon]]
+
+> It's a markdown bug. For some reason, markdown doesn't recognize the email with a '+' as an email:
+>
+> $ echo '<a+b@c.org>' | markdown
+> <p><a+b@c.org></p>
+>
+> htmlscrubber then (rightly) removes this unknown tag.
+>
+
+>> Filed [in CPAN](http://rt.cpan.org/Ticket/Display.html?id=37909)
+>> --[[Joey]] [[!tag done]]
+
+> But I've noticed some other Text::Markdown bugs that, even with htmlscrubber, produce
+> [ill-formed (X)HTML](http://validator.w3.org/check?uri=http%3A%2F%2Fikiwiki.info%2Fbugs%2Fmarkdown_bug%3A_email_escaping_and_plus_addresses%2F).
+> (View the markdown source of this page.)
+>
+> --Gabriel
+
+>> The htmlscrubber does not attempt to produce valid html from invalid. It
+>> attempts to prevent exploits in html. The tidy plugin can force html to
+>> valid. --[[Joey]]
+
+<tt>
+
+-
+>
--- mercurial.pm 2007-03-24 16:14:35.000000000 +0100
+++ /home/hbernard/mercurial.pm 2007-04-19 19:05:47.000000000 +0200
@@ -95,7 +95,7 @@
- sub rcs_add ($) { # {{{
+ sub rcs_add ($) {
my ($file) = @_;
- my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "add", "$file");
--- /dev/null
+I messed up my local clone of my repository.
+
+It appears that there is a special clone, which contains .ikiwiki, local.css, recentchanges, and the like.
+
+How can I create a new version of this clone?
+
+> No, there's the srcdir, which ikiwiki populates with some of those files
+> when run. Notably the .ikiwiki directory and all its contents, and the
+> recentchanges directory and its contents. But not local.css.
+>
+> If you've lost .ikiwiki and it contained user registration info
+> (passwords etc), you've lost that info. Everything else can be
+> regenerated by running `ikiwiki -setup your.setup`
+>
+> If you still have .ikiwiki, but the git clone is messed up somehow, you
+> can just make a new clone and move .ikiwiki into it before running
+> ikiwiki. --[[Joey]]
+
+> > Great, that worked. Thanks Joey!
+
+[[!tag done]]
--- /dev/null
+**problem description:** when using an external plugin like rst, the cgi script (but not the build process) fails with the following words:
+
+ Unsuccessful stat on filename containing newline at /usr/share/perl5/IkiWiki.pm line 501.
+ Unsuccessful stat on filename containing newline at /usr/share/perl5/IkiWiki.pm line 501.
+ Failed to load plugin IkiWiki::Plugin::</methodResponse>
+ : Can't locate IkiWiki/Plugin/.pm in @INC (@INC contains: /home/ikiwiki/.ikiwiki /etc/perl \
+ /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 \
+ /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .) at (eval 44) line 3.
+ BEGIN failed--compilation aborted at (eval 44) line 3.
+
+**setup used:** blank debian sid with ikiwiki 2.61 (but as the patch can be cleanly merged to git HEAD, i suppose this would happen on HEAD as well). perl version is 5.10.0-13.
+
+**problem analysis:** `strings ikiwiki.cgi` tells that the stored WRAPPED\_OPTIONS contain the string "</methodResponse>\n" where i'd expect "rst" in `config{add_plugins}`. this seems to originate in the use of `$_` in the plugin loading function.
+
+**patch comment:** solves the problem on 2.61. as these are the first lines of perl i've knowingly written, i can not explain what exactly was happening there.
+
+> Perl's `$_` handling is the worst wart on it, or possibly any language.
+> Here it's an alias to the actual value in the array, and when deep
+> in the external plugin load code something resets `$_` to a different
+> value, the alias remains and it changes the value at a distance.
+>
+> Thanks for the excellent problem report, [[fixed|done]]. --[[Joey]]
+
+------------------------------------------------------------------------------
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index e476521..d43abd4 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -471,7 +471,11 @@ sub loadplugins () {
+ unshift @INC, possibly_foolish_untaint($config{libdir});
+ }
+
+ - loadplugin($_) foreach @{$config{default_plugins}}, @{$config{add_plugins}};
+ + my $pluginname;
+ + foreach $pluginname (@{$config{default_plugins}}, @{$config{add_plugins}})
+ + {
+ + loadplugin($pluginname);
+ + }
+
+ if ($config{rcs}) {
+ if (exists $IkiWiki::hooks{rcs}) {
--- /dev/null
+I'm just working on an updated solution to [[todo/automatic_use_of_syntax_plugin_on_source_code_files]] (see also [[plugins/contrib/highlightcode]] or [[plugins/contrib/sourcehighlight]]).
+
+I realised that this is going to have problems when you ask it to process `.c` and `.h` files with the same base name. e.g. `hello.c` and `hello.h`.
+
+I tested it briefly with `test.java` and `test.mdwn` just to see what would happen. Things got quite strange. The source-highlighting plugin was called (probably for the java file), but then when it calls `pagetype($pagesources{$page})` to figure out the file type, that function returns `mdwn`, which confuses things somewhat.
+
+> This is a known possible point of confusion. If there are multiple source
+> files, it will render them both, in an arbitrary sequence, so one "wins".
+> --[[Joey]]
+
+Anyway, I'm thinking about possible solutions. The best option I've come up with so far is: when registering an htmlize hook, add a new optional paramter 'keep_extension'. This would make a source file of `hello.c` generate a page with name `hello.c` rather than the current `hello`. This would keep the pages unique (until someone makes `hello.c.mdwn`...).
+
+Suggestions welcome.
+
+-- [[Will]]
+
+> Ok, this turned out not to be a hard change. [[patch]] is below. With this patch you can tell IkiWiki not to drop the suffix when you register a hook: `hook(type => "htmlize", id => $lang, call => \&htmlize, leavesuffix => 1);`
+
+>> I think that's a good solution to the problem that most syntax plugins
+>> have struggled with. It makes sense. It doesn't solve the case where
+>> you have source files without any extension (eg `Makefile`), but at
+>> least it covers the common cases.
+>>
+>> I'm going to be annoying and call it "keepextension", otherwise, applied
+>> as-is. --[[Joey]] [[done]]
+
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index 4e4da11..853f905 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -618,7 +618,7 @@ sub pagename ($) {
+
+ my $type=pagetype($file);
+ my $page=$file;
+ - $page=~s/\Q.$type\E*$// if defined $type;
+ + $page=~s/\Q.$type\E*$// if defined $type && !$hooks{htmlize}{$type}{leavesuffix};
+ return $page;
+ }
+
+ diff --git a/t/pagename.t b/t/pagename.t
+ index 96e6a87..58811b9 100755
+ --- a/t/pagename.t
+ +++ b/t/pagename.t
+ @@ -6,7 +6,7 @@ use Test::More tests => 5;
+ BEGIN { use_ok("IkiWiki"); }
+
+ # Used internally.
+ -$IkiWiki::hooks{htmlize}{mdwn}=1;
+ +$IkiWiki::hooks{htmlize}{mdwn}{call}=1;
+
+ is(pagename("foo.mdwn"), "foo");
+ is(pagename("foo/bar.mdwn"), "foo/bar");
+
+----
+
+I wonder if this patch will also be useful:
+
+> Reasonable, applied.
+
+ diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
+ index 752d176..3f1b67b 100644
+ --- a/IkiWiki/Render.pm
+ +++ b/IkiWiki/Render.pm
+ @@ -279,7 +279,11 @@ sub refresh () {
+ else {
+ $f=~s/^\Q$config{srcdir}\E\/?//;
+ push @files, $f;
+ - $exists{pagename($f)}=1;
+ + my $pagename = pagename($f);
+ + if ($exists{$pagename}) {
+ + warn(sprintf(gettext("Page %s has multiple possible source pages"), $pagename)."\n");
+ + }
+ + $exists{$pagename}=1;
+ }
+ }
+ },
--- /dev/null
+I have the following structure:
+
+## page0
+ # Page 0
+ \[[!inline raw="yes" pages="page1"]]
+
+## page1
+ # Page 1
+ \[[!inline pages="page2"]]
+
+## page2
+ # Page 2
+ test
+
+In this situation, a change in page 2 will trigger a rebuild of page1 but not of page0.
+
+ refreshing wiki..
+ scanning page2.mdwn
+ rendering page2.mdwn
+ rendering page1.mdwn, which depends on page2
+ done
+
+In my real world situation, page1 is actually listing all pages that match a certain tag and page0 is the home page.
+Whenever a page got tagged, it will appear on page1 but not on page0.
+
+Am I missing something? Is this a bug or Ikiwiki not supposed to support this use case?
+
+> Perhaps the inline plugin isn't being clever enough about dependencies -
+> strictly speaking, when a page is inlined with full content, the inlining
+> page should probably inherit all the inlined page's dependencies.
+> That might be prohibitively slow in practise due to the way IkiWiki
+> currently merges pagespecs, though - maybe the patches I suggested for
+> [[separating_and_uniquifying_pagespecs|todo/should_optimise_pagespecs]]
+> would help? --[[smcv]]
--- /dev/null
+The [[ikiwiki/directive/inline]] directive applies a template to each page-to-be-inlined, but the loop over the pages is in the Perl, not the template itself. This means if I want to wrap a container `<div>` or a `<table>` or whatever around the entire set of inlined pages, I can't do it by just editing the template. In fact, I think the only way to do it without hacking any Perl is with a wrapper template directive, e.g.
+
+ \[[!template id="wrapinline" pages="..."]]
+
+with a template definition like
+
+ <div id="foo">\[[!inline ... pages="<TMPL_VAR raw_pages>"]]</div>
+
+It would be much more convenient if the loop over pages happened in the template, allowing me to just stick whatever markup I want around the loop.
+
+> Unfortunatly, I don't think this can be changed at this point,
+> it would probably break a lot of stuff that relies on the current
+> template arrangement, both in ikiwiki's internals and in
+> people's own, customised inline templates. (Also, I have some plans
+> to allow a single inline to use different templates for different
+> sorts of pages, which would rely on the current one template per
+> page approach to work.)
+>
+> But there is a simple workaround.. the first template in
+> an inline has FIRST set, and the last one has LAST set.
+> So you can use that to emit your div or table top and bottom.
+>
+> [[done]] --[[Joey]]
--- /dev/null
+The git commit (in my `openid` branch) says it all:
+
+ Update IkiWiki::openiduser to work with Net::OpenID 2.x
+
+ openiduser previously used a constructor that no longer works in 2.x.
+ However, all we actually want is the (undocumented) DisplayOfURL function
+ that is invoked by the display method, so try to use that.
+
+This bug affects ikiwiki.info (my commits show up in [[RecentChanges]] as http://smcv.pseudorandom.co.uk/ rather than smcv [pseudorandom.co.uk]).
+
+> Cherry picked, thanks. --[[Joey]]
+
+Relatedly, the other commit on the same branch would be nice to have
+(edited to add: I've now moved it, and its discussion, to
+[[todo/pretty-print_OpenIDs_even_if_not_enabled]]). --[[smcv]]
+
+[[!tag done]]
--- /dev/null
+I've just renamed a page and received the following as a result:
+
+<p>
+<b>Successfully renamed users/jondowland.mdwn to users/jon.mdwn.</b>
+</p>
+<p>
+
+The following pages have been automatically modified to update their links to users/jon.mdwn:
+<ul>
+<li><a href="./../../tips/convert_mediawiki_to_ikiwiki/discussion/">discussion</a></li><li><a href="./../../tips/untrusted_git_push/discussion/">discussion</a></li></ul>...
+
+In this situation I think the link to pages should be expanded to show the entire path, since there is quite likely to be a lot of things like "discussion". -- [[users/Jon]]
+
+[[done]]
--- /dev/null
+basewiki_brokenlinks.t fails when running dpkg-buildpackage in non-English environment : it greps for an (non-)error message that is i18n'd. This of course does not happen when building in a proper chroot environment... which happens to fail as well, for other reasons, but this will be for another bug.
+
+The `LANG=` on line 9 does not seem to do what it's supposed to, go figure.
+
+I've never had to understand the Unix locales, so I randomly tried to replace `LANG=` in basewiki_brokenlinks.t with :
+
+- `LANG=C` : fails
+- `LANGUAGE=` : fails
+- `LANGUAGE=C` : works!
+
+> For maximum precedence it should have been LC_ALL=C. [[done]], I think... --[[smcv]]
--- /dev/null
+Suppose a wiki has a source page a.mdwn, which is then moved to a.wiki.
+(Suppose both the mdwn and wikitext plugins are enabled, so this changes how "a" is rendered.)
+Currently, when the wiki is refreshed, ikiwiki doesn't notice the change
+and the page is not rebuilt.
+
+I have a [[patch]] that fixes this.
+The relevant commit on [my Github fork of ikiwiki](http://github.com/gmcmanus/ikiwiki/) is:
+
+ b6a3b8a683fed7a7f6d77a5b3f2dfbd14c849843
+
+The patch (ab)uses`%forcerebuild`, which is meant for use by plugins.
+If, for some reason, a plugin deletes the page's entry in `%forcerebuild`, it won't be rebuilt.
+
+This patch uncovers another problem.
+Suppose a wiki has a source page "a" (no extension)
+which is then moved to "a.mdwn" (or vice versa).
+ikiwiki fails when trying to create a directory "a" where there is a file "a"
+(or vice versa).
+
+The same problem occurs if both "a" and "a.mdwn" exist in the wiki.
+
+> Thank you for looking into it!
+>
+> On the use of forcerebuild, I think it's acceptable; plugins that unset
+> it would break other plugins that set it, too.
+>
+> [[cherry-picked|done]] --[[Joey]]
--- /dev/null
+The [[plugins/pagecount]] plugin seems to be broken, as it claims there are
+\[[!pagecount ]] pages in this wiki. (if it's not 0, the bug is fixed)
+
+[[fixed|done]] --[[Joey]]
--- /dev/null
+I want match pages which have actually curly braces in the names (like this one), but this matches a lot of pages without the braces in their names :( :
+
+[[!inline show="3" feeds="no" archive="yes" pages="*_{*}_*"]]
+
+(note: the inline above has been restricted to 3 matches to keep this page
+concise. Hopefully it is still clear that this page is not in the output set,
+and the 3 pages in the output set do not contain curly braces in their
+titles).
+
+When escaped, it doesn't work at all:
+
+[[!inline show="3" feeds="no" archive="yes" pages="*_\{*}_*"]]
+
+[[!inline show="3" feeds="no" archive="yes" pages="*_{*\}_*"]]
+
+More tests:
+
+"\*{\*":
+
+[[!inline show="3" feeds="no" archive="yes" pages="*{*"]]
+
+"\*\\{\*":
+
+[[!inline show="3" feeds="no" archive="yes" pages="*\{*"]]
+
+> This is due to the current handling of quoting and escaping issues
+> when converting a pagespec to perl code. `safequote` is used to
+> safely quote an input string as a `q{}` quote, and it strips
+> curlies when doing so to avoid one being used to break out of the `q{}`.
+>
+> Alternative ways to handle it would be:
+>
+> * Escape curlies. But then you have to deal with backslashes
+> in the user's input as they could try to defeat your escaping.
+> Gets tricky.
+>
+> * Avoid exposing user input to interpolation as a string. One
+> way that comes to mind is to have a local string lookup hash,
+> and insert each user specified string into it, then use the hash
+> to lookup the specified strings at runtime. [[done]]
+>
+> --[[Joey]]
+
+Thank you! I'll try it. --Ivan Z.
+ }
return IkiWiki::FailReason->new("syntax error") if $@;
return $ret;
- } #}}}
+ }
</pre>
> Thanks, [[done]] --[[Joey]]
+[[!tag patch plugins/inline patch/core]]
+
The `IkiWiki::pagetitle` function does not respect title changes via `meta.title`. It really should, so that links rendered with `htmllink` get the proper title in the link text.
--[[madduck]]
+
+----
+
+It is possible to set a Page-Title in the meta-plugin, but that one isn't
+reused in parentlinks. This patch may fix it.
+
+<ul>
+<li> I give pagetitle the full path to a page.
+<li> I redefine the 'pagetitle'-sub to deal with it.
+<li> to maintain compatibility for IkiWikis without the meta-plugin, i added a 'basename' to the Original-pagetitle.
+</ul>
+
+<pre>
+diff -c /usr/share/perl5/IkiWiki/Render.pm.distrib /usr/share/perl5/IkiWiki/Render.pm
+*** /usr/share/perl5/IkiWiki/Render.pm.distrib Wed Aug 6 07:34:55 2008
+--- /usr/share/perl5/IkiWiki/Render.pm Tue Aug 26 23:29:32 2008
+***************
+*** 102,108 ****
+ $template->param(
+ title => $page eq 'index'
+ ? $config{wikiname}
+! : pagetitle(basename($page)),
+ wikiname => $config{wikiname},
+ content => $content,
+ backlinks => $backlinks,
+--- 102,108 ----
+ $template->param(
+ title => $page eq 'index'
+ ? $config{wikiname}
+! : pagetitle($page),
+ wikiname => $config{wikiname},
+ content => $content,
+ backlinks => $backlinks,
+
+diff -c /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm.distrib /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm
+*** /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm.distrib Wed Aug 6 07:34:55 2008
+--- /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm Tue Aug 26 23:19:43 2008
+***************
+*** 44,50 ****
+ "height_$height" => 1,
+ };
+ $path.="/".$dir;
+! $title=IkiWiki::pagetitle($dir);
+ $i++;
+ }
+ return @ret;
+--- 44,50 ----
+ "height_$height" => 1,
+ };
+ $path.="/".$dir;
+! $title=IkiWiki::pagetitle($path);
+ $i++;
+ }
+ return @ret;
+
+diff -c /usr/share/perl5/IkiWiki.pm.distrib /usr/share/perl5/IkiWiki.pm
+*** /usr/share/perl5/IkiWiki.pm.distrib Wed Aug 6 07:48:34 2008
+--- /usr/share/perl5/IkiWiki.pm Tue Aug 26 23:47:30 2008
+***************
+*** 792,797 ****
+--- 792,799 ----
+ my $page=shift;
+ my $unescaped=shift;
+
++ $page=basename($page);
++
+ if ($unescaped) {
+ $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : chr($2)/eg;
+ }
+
+diff -c /usr/share/perl5/IkiWiki/Plugin/meta.pm.distrib /usr/share/perl5/IkiWiki/Plugin/meta.pm
+*** /usr/share/perl5/IkiWiki/Plugin/meta.pm.distrib Wed Aug 6 07:34:55 2008
+--- /usr/share/perl5/IkiWiki/Plugin/meta.pm Tue Aug 26 23:30:58 2008
+***************
+*** 3,8 ****
+--- 3,9 ----
+ package IkiWiki::Plugin::meta;
+
+ use warnings;
++ no warnings 'redefine';
+ use strict;
+ use IkiWiki 2.00;
+
+***************
+*** 289,294 ****
+--- 290,319 ----
+ }
+ }
+
++ sub IkiWiki::pagetitle ($;$) {
++ my $page=shift;
++ my $unescaped=shift;
++
++ if ($page =~ m#/#) {
++ $page =~ s#^/##;
++ $page =~ s#/index$##;
++ if ($pagestate{"$page/index"}{meta}{title}) {
++ $page = $pagestate{"$page/index"}{meta}{title};
++ } else {
++ $page = IkiWiki::basename($page);
++ }
++ }
++
++ if ($unescaped) {
++ $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : chr($2)/eg;
++ }
++ else {
++ $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : "&#$2;"/eg;
++ }
++
++ return $page;
++ }
++
+ package IkiWiki::PageSpec;
+
+ sub match_title ($$;@) {
+
+</pre>
+
+----
+
+> A few quick notes about it:
+
+> - Using <code>inline</code> would avoid the redefinition + code duplication.
+> - A few plugins would need to be upgraded.
+> - It may be necessary to adapt the testsuite in `t/pagetitle.t`, as well.
+>
+> --[[intrigeri]]
+>
+>> It was actually more complicated than expected. A working prototype is
+>> now in my `meta` branch, see my userpage for the up-to-date url.
+>> Thus tagging patch. --[[intrigeri]]
+>>
+>>> Joey, please consider merging my `meta` branch. --[[intrigeri]]
+
+So, looking at your meta branch: --[[Joey]]
+
+* Inter-page dependencies. If page A links to page B, and page B currently
+ has no title, then A will display the link as "B". Now page B is modified
+ and a title is added. Nothing updates "A".
+ The added overhead of rebuilding every page that links to B when B is
+ changed (as the `postscan` hook of the po plugin does) is IMHO a killer.
+ That could be hundreds or thousands of pages, making interactive editing
+ way slow. This is probably the main reason I had not attempted this whole
+ thing myself. IMHO this calls for some kind of intellegent dependency
+ handler that can detect when B's title has changed and only rebuild pages
+ that link to B in that case.
+* Looks like some plugins that use `pagetitle` to format it for display
+ were not changed to use `nicepagetitle` (for example, rename).
+ But most of those callers intend to display the page name
+ as a title, but including the parent directories in the path. (Ie,
+ "renaming foo/page title to bar/page title" --
+ you want to know it's moved from foo to bar.) `nicepagetitle` does not
+ allow doing that since it always takes the `basename`.
+* I don't like the name `nicepagetitle`. It's not very descriptive, is it?
+ And it seems very confusing to choose whether to use the "nice" or original
+ version. My hope is that adding a second function is unnecessary.
+ As I understand it, you added a new function for two reasons:
+ 1) It needs the full page name, not basename.
+ 2) `titlepage(pagetitle($page))` reversability.
+
+ 1) If you look at all the callers
+ Of `pagetitle` most of them pass a complete page name, not just the
+ basename. In most cases `pagetitle` is used to display the full name
+ of the page, including any subdirectory it's in. So why not just make
+ it consitently be given the full name of the page, with another argument
+ specifying if we want to get back just the base name.
+
+ 2) I can't find any code that actually uses the reversability like that.
+ The value passed to `titlepage` always comes from some external
+ source. Unless I missed one.
+* The use of `File::Spec->rel2abs` is a bit scary.
+* Does it really make sense to call `pagetitle` on the meta title
+ in meta's `nicepagetitle`? What if the meta title is something like
+ "foo_bar" -- that would be changed to "foo bar".
+* parentlinks is changed to use `nicepagetitle(bestlink($page, $path))`.
+ Won't `bestlink` return "" if the parent page in question does not exist?
+* `backlinks()` is changed to add an additional `title` field
+ to the hash returned, but AFAICS this is not used in the template.
+* Shouldn't `Render.pm` use nicepagetitle when getting the title for the
+ page template? Then meta would not need to override the title in the
+ `pagetemplate` hook. (Although this would eliminate handling of
+ `title_overridden` -- but that is little used and would not catch
+ all the other ways titles can be overridden with this patch anyway.)
+
+> I'm not a reviewer or anything, but can I chime in on changes to pagetitle?
+> I don't think having meta-titles in wikilinks and the parentlinks path by
+> default is necessarily a good thing. I don't consider the meta-title of a page
+> as used in `<title>` to be the same thing as the short title you
+> want in those contexts - IMO, the meta-title is the "formal" title of the page,
+> enough to identify it with no other context, and frequently too long to be used
+> as a link title or a parentlink, whereas the parentlinks title in particular
+> should be some abbreviated form that's enough to identify it in context.
+> [tbm](http://www.cyrius.com/) expressed a similar opinion when I was discussing
+> ikiwiki with him at the weekend.
+>
+> It's a matter of taste whether wikilinks are "like a parentlink" or "like a
+> `<title>`"; I could be persuaded either way on that one.
+>
+> An example from my site: [this page](http://www.pseudorandom.co.uk/2004/debian/ipsec/)
+> is the parent of [this page](http://www.pseudorandom.co.uk/2004/debian/ipsec/wifi/)
+> with a title too long to use in the latter's parentlinks; I think the titles of
+> both those pages are too long to use as wikilink text too. Similarly, tbm's page
+> about [Debian on Orion devices from Buffalo](http://www.cyrius.com/debian/orion/buffalo/)
+> can simply be called "Buffalo" in context.
+>
+> Having a `\[[!meta abbrev="..."]]` that took precedence over title
+> in parentlinks and possibly wikilinks might be a good way to fix this? Or if your
+> preference goes the other way, perhaps a `\[[!meta longtitle=""]]` could take
+> precedence when generating the `<title>` and the title that comes after the
+> parentlinks. --[[smcv]]
+
+>> I think you've convinced me. (I had always had some doubt in my mind as
+>> to whether using titles in all these other places would make sense.)
+>>
+>> Instead of meta abbrev, you could have a meta pagename that
+>> overrides the page name displayed everywhere (in turn overridden by
+>> meta title iff the page's title is being displayed). But is this complexity
+>> needed? We have meta redir, so if you want to change the name of a page,
+>> you can just rename it, and put in a stub redirection page so links
+>> still work.
+>>
+>> This leaves the [[plugins/contrib/po]] plugin, which really does need
+>> a way to change the displayed page name everywhere, and at least a
+>> subset of the changes in the meta branch are needed to support that.
+>>
+>> (This would also get around my concern about inter-page dependency
+>> handling, since po contains a workaround for that, and it's probably
+>> acceptable to use potentially slow methods to handle this case.)
+>> --[[Joey]]
+
+>>> I'm glad to implement whatever decision we'll make, but I don't
+>>> clearly understand what this discussion's conclusion is. It seems
+>>> like we agree at least on one point: meta page titles shall not be
+>>> displayed all over the place by default; I have therefore disabled
+>>> `meta_overrides_page_title` by default in my `meta` branch.
+>>>
+>>> My next question is then: do we only want to satisfy the `po`
+>>> plugin needs? Or do we want to allow people who want this, such as
+>>> [[madduck]], to turn on a config switch so that meta page titles
+>>> are displayed as wikilinks titles? In the latter case, what level
+>>> of configurability do we want? I can think of a quite inelegant
+>>> way to implement full configurability, and provide a configuration
+>>> switch for every place where links are displayed, such as
+>>> wikilinks, parentlinks, etc., but I don't think the added bonus is
+>>> worth the complexity of it.
+>>>
+>>> I think we can roughly split the needs into three categories:
+>>>
+>>> 1. never display any modified page title in links; this is the
+>>> current behaviour, and we should keep it as the default one
+>>> 2. display modified page titles only at well chosen places; that
+>>> could be "manual" wikilinks, I mean those generated by the
+>>> `link`, `camelcase` & al. plugins, the recentchanges page, and
+>>> maybe a few other places; keep the usual pagename-based title
+>>> for every other link, such as the parentlinks ones.
+>>> The inter-page dependency problem remains, though. As a first
+>>> step, I'm in favour of the "slow, but correct" implementation,
+>>> with a big warning stating that enabling this option can make
+>>> a wiki really sluggish; if someone really wants this to work
+>>> fast, he/she'll implement a clever dependency handler :)
+>>> 3. display modified page titles all over the place; IMHO, we
+>>> should implement only the bits needed so that the `po` plugin
+>>> can set this up, rather than provide this as
+>>> a user-configurable option.
+>>>
+>>> So my question is: do we want to implement the #2 case, or not?
+>>> I propose myself to only implement #1 and #3 to start with, but do
+>>> it in a way that leaves room for #2.
+>>>
+>>> --[[intrigeri]]
+>>>
+>>>> I agree, we should concentrate on getting just enough functionality
+>>>> for the po plugin, because I want to merge the po plugin soon.
+>>>> If #2 gets tackled later, we will certianly have all kinds of fun.
+>>>> no matter what is done for the po plugin. --[[Joey]]
--- /dev/null
+[[!tag bugs wishlist]]
+
+Escaping pipe-symbol in [[taglink|ikwiki/directive/taglink]] targets doesn't work as I wanted:
+
+[[!taglink smth_with_a_pipe|about_the_\|-symbol]]
+[[!taglink smth_with_a_pipe|about_the_|-symbol]]
+
+as opposed to simple wikilinks:
+
+[[a link to smth with a pipe|about the \|-symbol]]
+[[a link to smth with a pipe|about the |-symbol]]
+
+And it seems to work in pagespecs:
+
+tagged:
+
+[[!map pages="tagged(about the |-symbol)"]]
+
+[[!map pages="tagged(about the \|-symbol)"]]
+
+link:
+
+[[!map pages="link(about the |-symbol)"]]
+
+[[!map pages="link(about the \|-symbol)"]]
See this example:
-[[table class=table1 data="""
+[[!table class=table1 data="""
aaaaaaaaaaaaaaa|b|c
--\|\|--|e|f
"""]]
--- /dev/null
+Was it intended that the po plugin add a new dependency?
+
+> Yes; see debian/control Build-Depends. However, I have made it disable
+> building that is po4a is not available. [[done]] --[[Joey]]
+
+ PERL5LIB=.. ./po2wiki underlay.setup
+ Failed to load plugin IkiWiki::Plugin::po: Can't locate Locale/Po4a/Common.pm in @INC (@INC contains: .. /Library/Perl/Updates/5.8.8 /System/Library/Perl/5.8.8/darwin-thread-multi-2level /System/Library/Perl/5.8.8 /Library/Perl/5.8.8/darwin-thread-multi-2level /Library/Perl/5.8.8 /Library/Perl /Network/Library/Perl/5.8.8/darwin-thread-multi-2level /Network/Library/Perl/5.8.8 /Network/Library/Perl /System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level /System/Library/Perl/Extras/5.8.8 /Library/Perl/5.8.6 /Library/Perl/5.8.1 /sw/lib/perl5/5.8.8/darwin-thread-multi-2level /sw/lib/perl5/5.8.8 /sw/lib/perl5/darwin-thread-multi-2level /sw/lib/perl5 /sw/lib/perl5/darwin /usr/local/lib/perl5/site_perl/5.8.8/darwin-thread-multi-2level /usr/local/lib/perl5/site_perl/5.8.8 /usr/local/lib/perl5/site_perl .) at ../IkiWiki/Plugin/po.pm line 13.
+ BEGIN failed--compilation aborted at ../IkiWiki/Plugin/po.pm line 13.
+ Compilation failed in require at (eval 27) line 2.
+ BEGIN failed--compilation aborted at (eval 27) line 2.
+
+ make[1]: *** [po2wiki_stamp] Error 2
+ make: *** [extra_build] Error 2
+
+And it looks like this dependency is not easy to work around. The issue is that the newly translated base wiki means that the po plugin is being used by the build system. It is no longer optional. I've turned it off in my workspace like this: (heavy handed, but it lets me keep going until a proper fix is available)
+
+ diff --git a/Makefile.PL b/Makefile.PL
+ index 602d8fb..68728b7 100755
+ --- a/Makefile.PL
+ +++ b/Makefile.PL
+ @@ -42,7 +42,7 @@ extra_build: ikiwiki.out ikiwiki.setup docwiki
+ ./mdwn2man ikiwiki-makerepo 1 doc/ikiwiki-makerepo.mdwn > ikiwiki-makerepo.man
+ ./mdwn2man ikiwiki-transition 1 doc/ikiwiki-transition.mdwn > ikiwiki-transition.man
+ ./mdwn2man ikiwiki-update-wikilist 1 doc/ikiwiki-update-wikilist.mdwn > ikiwiki-update-wikilist.man
+ - $(MAKE) -C po
+ + # $(MAKE) -C po
+
+ docwiki: ikiwiki.out
+ $(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -setup docwiki.setup -refresh
+ @@ -114,7 +114,7 @@ extra_install: underlay_install
+ install ikiwiki.out $(DESTDIR)$(PREFIX)/bin/ikiwiki
+ install ikiwiki-makerepo ikiwiki-transition ikiwiki-update-wikilist $(DESTDIR)$(PREFIX)/bin/
+
+ - $(MAKE) -C po install DESTDIR=$(DESTDIR) PREFIX=$(PREFIX)
+ + # $(MAKE) -C po install DESTDIR=$(DESTDIR) PREFIX=$(PREFIX)
+
+ # These might fail if a regular user is installing into a home
+ # directory.
--- /dev/null
+po files are not added to git (error: /path/to/po/file not in repository tree) in my setup.
+
+I have set absolute path for srcdir = '/path/to/repo/doc/'. The root of my git repository is '/path/to/repo/'. When I enable the po plugin, it creates all po files and produces an error when it try to add the file saying that the /path/to/repo/doc/index.fr.po is not in the repository tree.
+
+I have no problem when I use an relative path like srcdir = '.'.
+
+I have an other issue with the po plugin when I set the srcdir to './doc/' (provided that my config file is in /path/to/repo). In this case the po plugin try to add 'doc/doc/index.fr.po' which does not exists (seems like the srcdir path is prepended twice).
+
+> You should never use a relative srcdir path with ikiwiki.
+>
+> I wonder what version of git you have there, since it works ok with the
+> version I have here. But, the po plugin is definitly doing the wrong
+> thing; it's telling git to add the po file with the full scrdir path
+> rather than relative to its root. Fixed that. [[done]] --[[Joey]]
+
+>> Yeah, I figured for the relative path
+>> Git version 1.6.3.3 (on both my dev and server machines)
+>>
+>> Here is an example of what I get when I update the po file on my laptop and I push to the master repository:
+
+ From /srv/git/sb
+ 5eb4619..ecac4d7 master -> origin/master
+ scanning doc.fr.po
+ building doc.fr.po
+ building doc.mdwn, which depends on doc.fr
+ building recentchanges.mdwn, which depends on recentchanges/change_ecac4d7311b15a3a3ed03102b9250487315740bc
+ fatal: '/srv/www/sb.l.n/new/doc/doc.fr.po' is outside repository
+ 'git add /srv/www/sb.l.n/new/doc/doc.fr.po' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 161.
+ done
+ To ssh://git.lohrun.net/var/cache/git/songbook.git
+ 5eb4619..ecac4d7 master -> master
+
+>> The root repository used to run ikiwiki is `/srv/www/sb.l.n/new/`
+>> -- [[AlexandreDupas]]
--- /dev/null
+# post-commit hangs
+
+I installed ikiwiki v3.14159 in /usr/local from tarball (/usr contains an older version). Having done so, and used ikiwiki-transition to update setup file, the post commit hook is now blocking in flock (as seen by ps). I should also mention that I added the goodstuff, attachment and remove plugins (which was the purpose of upgrading to v3). Any clues as how to debug/fix gratefully received. The wiki is publically viewable at wiki.sgcm.org.uk if that helps.
+
+> It's blocking when you do what? Save a page from the web? Make a commit
+> to the underlaying VCS? Which VCS? These are all different code paths..
+> --[[Joey]]
+
+>> It's blocking when I run "ikiwiki --setup ikiwiki.setup" (which calls hg update, which calls ikiwiki --post-commit).
+>> Hmm, maybe it's the recursive call to ikiwiki which is the problem.
+>> The underlying VCS is mercurial. --Ali
+
+>>> You're not supposed to run ikiwiki -setup manually in your post commit hook.
+>>> Doing so will certianly lead to a locking problem; it also forces ikiwiki to rebuild
+>>> the entire wiki anytime a single page changes, which is very inefficient!
+>>>
+>>> Instead, you should use the `mercurial_wrapper` setting
+>>> in the setup file, which will make ikiwiki generate a small
+>>> executable expressly designed to be run at post commit time.
+>>> Or, you can use the `--post-commit` option, as documented
+>>> in [[rcs/mecurial]] --[[Joey]]
+
+>>>> I don't run ikiwiki --setup in the commit hook; I run ikiwiki --post-commit (as mentioned above).
+>>>> I'm trying to run ikiwiki --setup from the command line after modifying the setup file.
+>>>> ikiwiki --setup is calling hg update, which is calling ikiwiki --post-commit. Am I not supposed to do that? --Ali
+
+>>>>> No, I don't think that hg update should call ikiwiki anything. The
+>>>>> [[hgrc_example|rcs/mercurial]] doesn't seem to configure it to do that? --[[Joey]]
+
+>>>>>> Ok, I'm not sure I understand what's going on, but my problem is solved.
+>>>>>>
+>>>>>> My hgrc used to say:
+>>>>>>
+>>>>>> [hooks]
+>>>>>>
+>>>>>> incoming.update = hg up
+>>>>>>
+>>>>>> update.ikiwiki = ikiwiki --setup /home/ikiwiki/ikiwiki.setup --post-commit
+>>>>>>
+>>>>>> I've now changed it to match the example page and it works. Thanks --Ali.
+
+>>>>>>> [[done]]
+
+> Also, how have you arranged to keep it from seeing the installation in /usr? Perl could well be loading
+> modules from the old installation, and if it's one with a different locking strategy that would explain your problem. --[[Joey]]
+
+>> Good point. Not knowing perl, I just assumed /usr/local would take precedence. I've now used "dpkg -r ikiwiki" to remove the problem. --Ali
--- /dev/null
+Prettydate creates strings like this: _Last edited in the wee hours of Tuesday night, July 1st, 2009_. However, July 1st is a Wednesday, so either date or Weekday should be modified. In the spirit is probably _Tuesday night, June 30th_. --ulrik
+
+> The default prettydate times are fairly idiosyncratic to
+> how [[Joey]] thinks about time. Specifically, it's still
+> Tuesday night until he wakes up Wednesday morning -- which
+> could be in the afternoon. :-P But, Joey also realizes
+> that dates change despite his weird time sense, and so
+> July 1st starts at midnight on Tuesday and continues
+> through Tuesday night and part of Wednesday.
+>
+> (This might not be as idiosyncratic as I make it out to be..
+> I think that many people would agree that in the wee hours
+> of New Years Eve, when they're staggering home ahead of
+> the burning daylight, the date is already January 1st.)
+>
+> I think the bug here is that prettydate can't represent
+> all views of time. While the times
+> of day can be configured, and it's possible to configure it
+> to call times after midnight "Wednesday morning, July 1st",
+> it is not possible to configure the date or weekday based
+> on the time of day.
+>
+> In order to do so, prettydate's timetable would need to be
+> extended to include the "%B %o, %Y" part, and that extended
+> to include "%B-", "%o-", and "%Y-" to refer to the day
+> before.
+>
+> --[[Joey]]
+
+>> fair enough, I think I can get converted to a warped time perspective. --ulrik
+
+>>> Perhaps we can consider this [[done]], then? --[[smcv]]
--- /dev/null
+Steps to reproduce:
+
+1. Make a new post via web interface.
+2. Use a directive that generates extra files (say, teximg).
+3. Click cancel.
+
+What I expect:
+
+The files that teximg created should (eventually) be removed, along with the whole directory of the non-existant new post.
+
+What I got:
+
+I refresh and rebuild a few times, and the files are still dangling there. If I then try to create a post with the same name and same content, I get a "file independently created, not overwriting" error.
+
+> This is specific to previewing when creating a new page. If the page
+> previously existed, the next update to the page will remove the stale
+> preview files.
+>
+> Problem is that ikiwiki doesn't store state about files rendered by a
+> page if the page doesn't exist yet.
+>
+> However, just storing that state wouldn't entirely solve the problem,
+> since it would still not delete the leftovers until the page is updated,
+> which it never is if it's previewed and then canceled. And requiring the
+> cancel button be hit doesn't solve this, because people won't.
+>
+> Also, it's not really ideal that an existing page has to be updated to
+> remove stale files, because if the edit is aborted, the page might not be
+> updated for a long time.
+>
+> One fix would be to stash a copy of `%renderedfiles` before generating
+> the preview, then compare it afterwards to see how it changed and
+> determine what files were added, and record those someplace, and delete
+> them on a future refresh (after some reasonable time period). [[done]]
+>
+> Another approach would be to make previewing always render files with
+> some well-known temporary name. Then all such temp files could be removed
+> periodically. This would need changes to all plugins that write files
+> during preview though. For example, `will_render` might be changed to
+> return the actual filename to write to. --[[Joey]]
+
+For teximg, I think this can be fixed by using data url like graphviz, but
+I think plugins in general should be allowed to create files during preview
+and have them be cleaned up when the user presses cancel. This segues into
+what my actual problem is: I wrote a htmlize plugin to format .tex files as
+page images (following hnb and teximg, since I was completely unfamiliar
+with perl until yesterday (and ikiwiki until a few days ago)), and there is
+no way to tell if I'm in preview mode (so I can use data url and not leave
+files dangling) or commit mode (so I can use real images and not have
+bloated html).
+
+> It seems too ugly to thread an indicator to preview mode through to
+> htmlize, so I'd prefer to not deal with the problem that way.
--- /dev/null
+The 'editcontent' textarea that should be saved across previews is being overridden whenever an edittemplate is in use, 'losing' edits on preview unless the browser maintains them in history.
+
+ --[[JoeRayhawk]]
+
+> ugly one... [[done]] --[[Joey]]
<pre>
use Scalar::Util qw(tainted);
-sub prune ($) { #{{{
+sub prune ($) {
my $file=shift;
unlink($file);
$dir = $1;
}
}
-} #}}}
+}
</pre>
> Old versions of perl are known to have bugs with taint checking.
> I don't really support using ikiwiki with the perl 5.8.4 in debian
> oldstable, and would recommend upgrading. --[[Joey]]
-[[tag patch done]]
+[[!tag patch done]]
@@ -55,7 +55,7 @@
}
- sub rcs_update () { #{{{
+ sub rcs_update () {
- my @cmdline = ("hg", "-R", "$config{srcdir}", "update");
+ my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update");
if (system(@cmdline) != 0) {
if (system(@cmdline) != 0) {
warn "'@cmdline' failed: $!";
@@ -92,7 +92,7 @@
- sub rcs_add ($) { # {{{
+ sub rcs_add ($) {
my ($file) = @_;
- my @cmdline = ("hg", "-R", "$config{srcdir}", "add", "$file");
I have to suspect that replacing html with some hash is a bug.
-> Congrats, you're another person to fall afoul of markdown [[debbug 380212]].
+> Congrats, you're another person to fall afoul of markdown [[!debbug 380212]].
> The fix is to use Text::Markdown, or markdown 1.0.2 instead of buggy
-> old markdown 1.0.1. --[[Joey]] [[tag done]]
+> old markdown 1.0.1. --[[Joey]] [[!tag done]]
## inlining raw html
--- /dev/null
+When committing a page like this one, with an escaped toc directive in it:
+
+ \[[!toc ]]
+
+The recentchangesdiff comes back with it unescaped. Which can be confusing.
>>> todo about [[todo/ability_to_force_particular_UUIDs_on_blog_posts]],
>>> and then by just using that new ability in the page. --[[Joey]]
->>>> Ah. The prerequisite todo looks like more than I'd like to take on.
+>>>> <del title="Prerequisite done now?">Ah. The prerequisite todo looks like more than I'd like to take on.
>>>> In the meantime, would it be very involved to change whatever bug now
>>>> optimizes away the change pages, or to simply have all the links in the
>>>> feed point to the recentchanges page itself, with no fragment id?
->>>> Either would be a bit nicer than having broken links in the feed. --Chap
+>>>> Either would be a bit nicer than having broken links in the feed. --Chap</del>
+
+>>>> Does the completion of that todo mean it would be straightforward to get
+>>>> recentchanges working now? Is it just that the recentchanges plugin
+>>>> needs to generate `\[[!meta guid=something]]` into the internal files,
+>>>> and the inline plugin would then generate working links in feeds? How should
+>>>> the guid be constructed? Something based on the rcs revision number? I guess
+>>>> I'm still not completely clear on your vision for how it ought to work. --Chap
+
+>>>> My idea is to use `\[[meta guid="http://url/recentchanges#rev"]]`, with the
+>>>> `#rev` anchor also included in the change file, and being the rcs's
+>>>> internal revision id. Then the guid is globally unique, and actually
+>>>> links to the change in the recentchanges page. And, when the change
+>>>> has fallen off the page, the link will still go to the recentchanges page.
+>>>>
+>>>> First, need to check that guids in rss and atom feeds can have anchors in
+>>>> them, and that the anchor is treated as part of the guid. (If the guid
+>>>> is interpreted as just "http://url/recentchanges", then it's
+>>>> not a very good guid.) If using an anchor for a guid is a problem,
+>>>> it could instead generate a random uuid, and use `\[[meta
+>>>> guid="urn:uuid:<foo>" permalink="http://url/recentchanges"]]`
+
+>>>>> I had a quick look into this after fixing the "prerequisite", but got
+>>>>> bogged down in minor details. Anyway, I'd be happy to help.
+>>>>> I think the guid stuff is actually fairly irrelevant, you just need
+>>>>> `\[[!meta permalink]]` (and in fact you're using guid incorrectly, by
+>>>>> expecting it to be treated as a link).
+>>>>>
+>>>>> My advice would be: first, fix the bug as reported, by
+>>>>> using `\[[!meta permalink="http://blah/blah/blah#change-$rev"]]` (starting
+>>>>> anchor names with a number isn't syntactically valid, if I remember
+>>>>> correctly, so do have a prefix like "change-" or "rev-" or something).
+>>>>>
+>>>>> Then, optionally, force the guid too (although it defaults to the permalink
+>>>>> anyway, so this shouldn't actually be necessary).
+>>>>>
+>>>>> Some more explanation of how guids work: it's actually easier to think
+>>>>> about them in Atom terms than in RSS terms, since Atom has a clearer
+>>>>> conceptual model.
+>>>>>
+>>>>> The `\[[!meta permalink]]` becomes the `<link>`
+>>>>> element in Atom, which contains a link that users can follow; if it's not
+>>>>> explicitly given, ikiwiki uses its idea of the page's URL.
+>>>>>
+>>>>> The `\[[!meta guid]]` becomes the `<id>` element in Atom, which contains an
+>>>>> opaque, not-necessarily-resolvable identifier; if it's
+>>>>> not explicitly given, ikiwiki uses the same URL as the `<link>`.
+>>>>>
+>>>>> In RSS the semantics aren't so clear-cut (which is part of why Atom exists!),
+>>>>> but the way ikiwiki interprets them is:
+>>>>>
+>>>>> * `<link>` is the same as in Atom
+>>>>> * if `\[[!meta guid]]` is explicitly given, put it in `<guid permalink="no">`
+>>>>> (the assumption in this case is that it's a UUID or something)
+>>>>> * if `\[[!meta guid]]` is not explicitly given, copy the `<link>` into the `<guid>`
+>>>>>
+>>>>> I believe RSS aggregators (are meant to) compare `<guid>`s as opaque
+>>>>> strings, so using an anchor there should be fine. Atom aggregators are certainly
+>>>>> required to compare `<id>`s as opaque strings.
+>>>>>
+>>>>> --[[smcv]]
+
+>>>>>> Here's my attempt at a [[patch]] for anchor-based change permalinks:
+>>>>>> <http://pastie.org/295016>.
+>>>>>> --[[JasonBlevins]], 2008-10-17
+
+[[JasonBlevins]] nailed it, [[done]] --[[Joey]]
+
+> Thanks for applying the patch (and improving it). There's still one small issue:
+> the old opening div tag still needs to be removed (it's hard to see the removed line
+> with the pastie color scheme).
+> --[[JasonBlevins]], 2008-10-18
+
+>> Thanks, missed that when I had to hand-apply the patch. --[[Joey]]
> I only see it with 1.0.1. (Bad news: Newer versions of markdown are
> slooooooow, especially on such large files.)
-> I'm calling this [[done]] since I've filed [[debbug 470676]] on perl, and
+> I'm calling this [[done]] since I've filed [[!debbug 470676]] on perl, and
> also have modified recentchangesdiff to only show the first 200 lines of
> diff, which should be enough without bloating the recentchanges into
> perl-crashing territory. --[[Joey]]
--- /dev/null
+I just submitted a new bug, and... after clicking "save", my brand new bug page displays, at the bottom: "Last edited 6 hours and 3 minutes ago". Timezone issue, I guess? (Hint: I'm in France) -- [[intrigeri]]
+
+> Yep, it wasn't including a timezone in the machine parseable time.
+> [[done]] --[[Joey]]
+++ /dev/null
-It looks like all links in websites are absolute paths, this has some limitations:
-
-* If connecting to website via https://... all links will take you back to http://
-* Makes it harder to mirror website via HTML version, as all links have to be updated.
-
-It would be good if relative paths could be used instead, so the transport method isn't changed unless specifically requested.
-
--- Brian May
-
-> Er, which absolute links are you talking about? If you view the source
-> to this page, you'll find links such as "../favicon.ico", "../style.css",
-> "../../", and "../". The only absolute links are to CGIs and the w3c DTD.
-> --[[Joey]]
-
->> The problem is within the CGI script. The links within the HTML page are all absolute, including links to the css file.
->> Having a http links within a HTML page retrieved using https upset most browsers (I think). Also if I push cancel on the edit page in https, I end up at at http page. -- Brian May
-
->>> Ikiwiki does not hardcode http links anywhere. If you don't want
->>> it to use such links, change your configuration to use https
->>> consistently. --[[Joey]]
-
-Errr... That is not a solution, that is a work around. ikiwiki does not hard code the absolute paths, but absolute paths are hard coded in the configuration file. If you want to serve your website so that the majority of users can see it as http, including in rss feeds (this allows proxy caches to cache the contents and has reduced load requirements), but editing is done via https for increased security, it is not possible. I have some ideas how this can be implemented (as ikiwiki has the absolute path to the CGI script and the absolute path to the destination, it should be possible to generate a relative path from one to the other), although some minor issues still need to be resolved. -- Brian May
-
-I noticed the links to the images on <http://ikiwiki.info/recentchanges/> are also absolute, that is <http://ikiwiki.info/wikiicons/diff.png>; this seems surprising, as the change.tmpl file uses <TMPL_VAR BASEURL>
-which seems to do the right thing in page.tmpl, but not for change.tmpl. Where is BASEURL set? -- Brian May
-
-> The use of an absolute baseurl in change.tmpl is a special case. --[[Joey]]
--- /dev/null
+Hi!
+
+How about to replace sparkline-php from Suggests by a better alternative?
+
+I would like to file a RM bug to get it out of archive. Do you have a better alternative for it? PHP has a lot of them..
+
+Thanks
+
+> sparline-php is orphaned *in Debian*. Upstream, is has seen activity as
+> recently as 11 months ago.
+>
+> I don't know of a better alternative. I looked at the perl sparkline
+> stuff in CPAN and is was bad enough that the pain of using php from this
+> perl program was a better alternative.
+>
+> Anyway, it works great; maintaining the sparkline-php package in Debian
+> would certianly be much less work than finding some alternative and
+> rewriting the ikiwiki code to use it, *and* packaging that alternative
+> and maintaining it in Debian. So your suggestion doesn't make a lot of
+> sense; Debian should just find a maintainer for sparkline-php. --[[Joey]]
--- /dev/null
+The [[plugins/remove]] plugin does not report an error if git rm fails. (It
+probably doesn't if other VCS backends fail too). This can happen for example
+if a page in your source directory is not a tracked file for whatever reason
+(in my case, due to renaming the files and forgetting to commit that change).
+
+ -- [[Jon]]
--- /dev/null
+The Atom and RSS templates use `ESCAPE=HTML` in the title elements. However, HTML-escaped characters aren't valid according to <http://feedvalidator.org/>.
+
+Removing `ESCAPE=HTML` works fine, but I haven't checked to see if there are any characters it won't work for.
+
+For Atom, at least, I believe adding `type="xhtml"` to the title element will work. I don't think there's an equivalent for RSS.
+
+> Removing the ESCAPE=HTML will not work, feed validator hates that just as
+> much. It wants rss feeds to use a specific style of escaping that happens
+> to work in some large percentage of all rss consumers. (Most of which are
+> broken).
+> <http://www.rssboard.org/rss-profile#data-types-characterdata>
+> There's also no actual spec about how this should work.
+>
+> This will be a total beast to fix. The current design is very clean in
+> that all (well, nearly all) xml/html escaping is pushed back to the
+> templates. This allows plugins to substitute fields in the templates
+> without worrying about getting escaping right in the plugins -- and a
+> plugin doesn't even know what kind of template is being filled out when
+> it changes a field's value, so it can't do different types of escaping
+> for different templates.
+>
+> The only reasonable approach seems to be extending HTML::Template with an
+> ESCAPE=RSS and using that. Unfortunately its design does not allow doing
+> so without hacking its code in several places. I've contacted its author
+> to see if he'd accept such a patch.
+>
+> (A secondary bug is that using meta title currently results in unnecessry
+> escaping of the title value before it reaches the template. This makes
+> the escaping issues show up much more than they need to, since lots more
+> characters are currently being double-escaped in the rss.)
+>
+> --[[Joey]]
+
+> Update: Ok, I've fixed this for titles, as a special case, but the
+> underlying problem remains for other fields in rss feeds (such as
+> author), so I'm leaving this bug report open. --[[Joey]]
@staticmethod
-[[tag patch]]
-
> No, still the same failure. I think it's failing parsing the input data,
> (which perl probably transmitted as an int due to perl internals)
> not writing out its response. --[[Joey]]
it's a problem with the XML-RPC interface.
Sorry for the delay, this is now fixed! --[[Joey]]
-[[tag done]]
+[[!tag done]]
print html[html.find('<body>')+6:html.find('</body>')].strip();
";
</pre>
+
+----
+
+Does the Perl version of this plugin still exist? There appears to be no "rst.pm" in the current distribution; all there is is the python version. --Peter
+
+> No, only the python version exists. It does have `raw_enabled` set.
+> --[[Joey]]
+
+I am sorry, but I am confused. Does this mean that I can use Ikiwiki
+features that translate to HTML in rst files? For example, when I use a
+\[[pagename]]-style link in a rst file, the page generated by Ikiwiki's rst
+plugin says <a href="./../pagename/">pagename</a> as text. The link
+is expanded correctly, but the result isn't interpreted as HTML. Is that
+what is supposed to happen? --Peter
+
+> `raw_enabled` allows you to use the
+> [raw directive](http://docutils.sourceforge.net/docs/ref/rst/directives.html),
+> but this is not used by ikiwiki for wikilinks or anything else.
+> That's why the [[plugin_page|plugins/rst]] has its note about
+> issues with wikilinks and directives. You'd have to put those inside
+> raw directives yourself to avoid rst escaping their result. --[[Joey]]
--- /dev/null
+Currently, ikiwiki indexes the "title" and "link" fields of a page
+using the prefix "Z".
+This is incorrect.
+"Z" is for stemmed terms,
+which xapian inserts itself.
+Furthermore, the custom field "LINK" should use the "X" prefix.
+(This is according to the [xapian-omega documentation] [xapian].)
+
+I have a [patch][] that fixes this.
+Once it is applied,
+the wiki should be rebuilt to fix the search index.
+
+What problems does the current behaviour cause?
+Consider the [[tags]] page.
+ikiwiki indexes the term "ZStags" for its title.
+xapian stems this and also indexes "ZZStag".
+(Notice the additional "Z".)
+Now when [searching for "title:tags"] [search],
+xapian stems this and searches for "ZStag",
+and so only finds pages which were indexed by _ikiwiki_ with "ZStag"
+(i.e. those pages with the singular "tag" in the title).
+
+--Gabriel.
+
+[xapian]: http://xapian.org/docs/omega/termprefixes.html
+ [patch]: http://www.gmcmanus.org/0001-Use-correct-term-prefixes-when-searching.patch
+[search]: http://ikiwiki.info/ikiwiki.cgi?P=title%3Atags
+
+[[!tag done]]
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
- @@ -1057,6 +1057,7 @@ sub gettext { #{{{
+ @@ -1057,6 +1057,7 @@ sub gettext {
$gettext_obj=undef;
return shift;
}
return $gettext_obj->get(shift);
}
-[[tag patch]]
+[[!tag patch patch/core]]
-- [[ThomasBleher]]
> According to my testing, this patch makes ikiwiki's localisation fail for
--- /dev/null
+Text on a page gets indexed when you preview.
+
+I discovered this by using (perhaps this is weird) the Sandbox to
+preview my markup in a file that I was preparing to check in through svn.
+I just deleted the original Sandbox text in the edit form, pasted in my
+file, hit Preview, then cancelled the edit, leaving the Sandbox unchanged.
+
+After that, the Sandbox was one of the search hits for terms in the new
+page, and the Sandbox excerpt in the search results showed text taken
+from the new page, that was never really in the Sandbox page at all.
+
+Clicking Edit and then Preview on the original Sandbox page corrected
+the problem, of course.
+
+Making the indexing only happen on a real commit might also speed the
+Preview up a small amount.
+--Chapman Flack
+
+[[!tag done]]
e.g. use "wikibase" for css and favicon and "baseurl" for the <base> tag.
> thanks for pointing this bug out, I've fixed it --[[Joey]].
-[[tag done]]
+[[!tag done]]
Might this be a problem of the web server?
Also, I'd like to put the shortcut usages into backticks
--- `[[iki shortcuts]]` --
+-- `[[!iki shortcuts]]` --
to have them displayed in the usual backtick-formatting.
That also doesn't work, but this is an already-reported issue, as far as I know.
--- /dev/null
+On my initial ikiwiki -setup auto.setup, I get the following error:
+
+ shortcut plugin will not work without shortcuts.mdwn
+ /home/turian/utils/etc/ikiwiki/auto.setup: ikiwiki --refresh --setup /home/turian/iki.setup failed at IkiWiki/Setup/Automator.pm line 105.
+
+
+This is using the latest git pull of ikiwiki.
+I am not sure why it is not finding shortcuts.mdwn. -- [[JosephTurian]]
+
+> The error, and the weird paths suggest to me that you
+> have installed ikiwiki in a strange way, and it is failing
+> to find its basewiki underlay. The `$installdir` is
+> hardcoded into IkiWiki.pm at build time, based on the PREFIX
+> setting (see README).
+>
+> If that's not set right, you'll have other problems than just this one,
+> so I suggest you check how you installed ikiwiki.
+>
+> Anyway, I've made the shortcut plugin only warn about this..
+> --[[Joey]]
+
+> > I have
+> > $installdir="/home/turian/utils/"
+> > and the underlay dir is set to:
+> > "$installdir/share/ikiwiki/basewiki",
+> > which does contain shortcuts.mdwn. So I am not sure why it is not finding it.
+> > I am grappling with installing ikiwiki in a user account, and would like to get the directories set up correctly.
+> > How can I debug this issue further?
+
+>>>> Why don't you strace it and look at where it's looking for
+>>>> shortcuts.mdwn. --[[Joey]]
+
+>>>>>> Hmm, so change the PERL5LIB seemed to fix this. [[Done]].
-Writing [[wikipedia Low_frequency_oscillation]] causes the word "frequency"
+Writing [[!wikipedia Low_frequency_oscillation]] causes the word "frequency"
to show up in italics, since underscores are Markdown for italics. Using
-[[wikipedia low frequency oscillation]] works in this case, because Wikipedia
+[[!wikipedia low frequency oscillation]] works in this case, because Wikipedia
will redirect, but it's hardly clean. Maybe the shortcuts plugin should
run pagetitle() on the text of its link? --Ethan
--- /dev/null
+I've set up a simple sidebar on an otherwise fairly default wiki. The sidebar uses css float:right and sits above most pages quite nicely.
+
+For example, my wiki's [front](http://www.cse.unsw.edu.au/~cs3431/wiki/) and [news](http://www.cse.unsw.edu.au/~cs3431/wiki/news/) pages show the sidebar nicely floating on top of the background. (As a side note, I had to add:
+
+ #sidebar {
+ border: 1px solid;
+ background: white;
+ }
+
+to <code>local.css</code> to get the border and make sure that the RSS feed's grey title didn't show through on the news page.)
+
+> Hmm the background color setting seems like a change it makes sense to make to
+> style.css .. done.
+> --[[Joey]]
+
+Unfortunately, the [recentchanges](http://www.cse.unsw.edu.au/~cs3431/wiki/recentchanges/) page doesn't look so nice - the sidebar appears below the recentchanges list.
+
+I don't understand why the sidebar is appearing below the recentchanges inline, but above the news inline.
+
+> I don't see the problem here in firefox 3. The sidebar is at the top of
+> both pages. However, it might have to do with the recentchanges page
+> itself using floating elements to build up the table-like display. --[[Joey]]
+
+>> I didn't test in firefox. I now have screenshots for both firefox and safari. It is still interesting to compare the layout. The first is quite broken. The second is only a little broken. The third is what I was expecting.
+
+Here is a screenshot of the broken behaviour in Safari:
+
+<img src="http://www.cse.unsw.edu.au/~willu/screenshots/safari-1.png" alt="screenshot of broken behaviour in Safari" width="50%" />
+
+Here is a screenshot of the same thing in FireFox. Notice that while there are no overlaps, there is still a large gap in the layout.
+
+<img src="http://www.cse.unsw.edu.au/~willu/screenshots/firefox-1.png" alt="screenshot of semi-working behaviour in Firefox" width="50%" />
+
+Here is an inline news page (in Safari, but it looks similar in firefox). I was expecting both of the previous layouts to look like this.
+
+<img src="http://www.cse.unsw.edu.au/~willu/screenshots/safari-2.png" alt="screenshot of working behaviour in Safari" width="50%" />
+
+What really surprises me is WHY this looks any different. And when you look at style.css you see that recentchanges and sidebar both use float, whereas normal inline pages do not.
+Note that in the third (working) screenshot, the top bullet point is wrapped. This is because the sidebar is floated.
+
+I think there is:
+
+ * A display bug in safari, and
+ * It would be nice to clean up the way recentchanges are displayed so that there isn't a vertical gap for the sidebar. I'll play with this and see what I can do.
+
+Looked at this a little more. I've found the following. Here is my current local.css:
+
+ div.recentchanges {
+ clear: both;
+ overflow: visible;
+ }
+
+Adding "clear: both;" makes the recentchanges div start below (as in further down the page) the sidebar. This makes safari behave like firefox above (changes the 1st screenshot to look more like the 2nd screenshot).
+
+Adding "overflow: visible;" (or removing "overflow: auto" from style.css) makes the sidebar appear above (as in printed over the top of, not higher up the page) the recentchanges (similar to the third screen shot above). Unfortunately because ".recentchanges .pagelinks" uses "float: right;" it looks strange in other ways. For this reason I use the "clear:both;" as well.
+
+-- [[users/Will]]
+
+>> Looks like [[Joey]] has added `clear:both;` to style.css, so this is [[bugs/done]]. -- [[Will]]
--- /dev/null
+A lot of strings in ikiwiki are hardcoded and not taken for locales resources through gettext. This is bad because ikiwiki is thus difficult to spread for non-english users.
+
+I mean that, for instance in CGI.pm, line like:
+
+`my @buttons=("Save Page", "Preview", "Cancel");`
+
+should be written as
+
+`my @buttons=(gettext("Save Page"), gettext("Preview"), gettext("Cancel"));`
+
+> Yes, these need to be fixed. But note that the localised texts come back
+> into ikiwiki and are used in various places, including plugins.
+> Including, possibly, third-party plugins. So localising the buttons would
+> seem to require converting from the translations back into the C locale
+> when the form is posted. --[[Joey]]
+
+>> Wouldn't it be more easy to change all calls to the corrects ones (including in plugins) ?
+>> For instance in the same file (CGI.pm): `elsif ($form->submitted eq gettext("Save Page")) {`.
+>> That way no conversion to the C locale is needed.
+>> gettext use should just be publicized in documentation (at least in [[plugins/write]]). --[[bbb]]
+
+>>> It would be easy, but it could break third-party plugins that hardcode
+>>> the english strings. It's also probably less efficient to run gettext
+>>> over and over. --[[Joey]]
+
+In standards templates things seems wrongly written too. For instance in page.tmpl line like:
+
+`<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>`
+
+should be written as
+
+`<li><a href="<TMPL_VAR EDITURL>" rel="nofollow"><TMPL_VAR EDITURL_TEXT</a></li>`
+
+with EDITURL_TEXT variable initialized in Render.pm through a gettext call.
+
+Am I wrong ?
+
+> No, that's not a sane way to localise the templates. The templates can be
+> translated by making a copy and modifying it, or by using a tool to
+> generate .mo files from the templates, and generate translated templates
+> from .po files. (See [[todo/l10n]] for one attempt.) But pushing the
+> localisation of random strings in the templates through the ikiwiki
+> program defeats the purpose of having templates at all. --[[Joey]]
+
+If not I can spend some time preparing patches for such corrections if it can help.
+
+-- [[/users/bbb]]
I attempted to make a new webpage by having wiki code with
- [[new page]]
+ [[!new page]]
[newpage]
This was converted to literal:
- [[new page]]
+ [[!new page]]
and the correct hyperlink:
?newpage
So when has a space it doesn't let you create a new page. I am using 1.35. Let's see what happens here:
-[[new page]]
+[[!new page]]
A moment later ... same thing ... it is not a link (no question mark to create).
-Having read i18n_characters_in_post_title, I have a page named `St John's` in a file named `St_John__39__s.mdwn`. Regular wikilinks like `\\[[St_John's]]` successfully point to that page. However, if I tag a page with `\[[tag St_John's]]`, that link is shown as pointing to a non-existant page. Modify the tag to read `\[[tag St_John__39__s]]` works around the problem.
+Having read i18n_characters_in_post_title, I have a page named `St John's` in a file named `St_John__39__s.mdwn`. Regular wikilinks like `\\[[St_John's]]` successfully point to that page. However, if I tag a page with `\[[!tag St_John's]]`, that link is shown as pointing to a non-existant page. Modify the tag to read `\[[!tag St_John__39__s]]` works around the problem.
[[done]] in 1.49 --[[Joey]]
> ikiwiki) performing any sanity checking of the openid server. All the
> security authentication goes on between your web browser and the openid
> server. This may involve ssl, or not.
+>
+>> Note that I'm not an openid expert, and the above may need to be taken
+>> with a grain of salt. I also can make no general statements about openid
+>> being secure. ;-) --[[Joey]]
>
> For example, my openid is "http://joey.kitenet.net/". If I log in with
> this openid, ikiwiki connects to that http url to determine what openid
> is good.
> --[[Joey]]
-[[tag done]]
+>> Ok, so I guess the worst that could happen when ikiwiki talks to the http
+>> address is that it gets intercepted, and ikiwiki gets the wrong address.
+>> ikiwiki will then redirect the browser to the wrong address. An attacker could
+>> trick ikiwiki to redirect to their site which always validates the user
+>> and then redirects back to ikiwiki. The legitimate user may not even notice.
+>> That doesn't so seem secure to me...
+
+>> All the attacker needs is access to the network somewhere between ikiwiki
+>> and http://joey.kitenet.net/ or the ability to inject false DNS host names
+>> for use by ikiwiki and the rest is simple.
+
+>> -- Brian May
+
+>>> I guess that the place to add SSL cert checking would be in either
+>>> [[!cpan LWPx::ParanoidAgent]] or [[!cpan Net::OpenID::Consumer]]. Adding
+>>> it to ikiwiki itself, which is just a user of those libraries, doesn't
+>>> seem right.
+>>>
+>>> It's not particularly clear to me how a SSL cert can usefully be
+>>> checked at this level, where there is no way to do anything but
+>>> succeed, or fail; and where the extent of the check that can be done is
+>>> that the SSL cert is issued by a trusted party and matches the domain name
+>>> of the site being connected to. I also don't personally think that SSL
+>>> certs are the right fix for DNS poisoning issues. --[[Joey]]
+
+I was a bit vague myself on the details on openid. So I looked up the standard.
+I was surprised to note that they have already considered these issues, in
+section 15.1.2, <http://openid.net/specs/openid-authentication-2_0.html#anchor41>.
+
+It says:
+
+"Using SSL with certificates signed by a trusted authority prevents these kinds of
+attacks by verifying the results of the DNS look-up against the certificate. Once
+the validity of the certificate has been established, tampering is not possible.
+Impersonating an SSL server requires forging or stealing a certificate, which is
+significantly harder than the network based attacks."
+
+With regards to implementation, I am surprised that the libraries don't seem to
+do this checking, already, and by default. Unfortunately, I am not sure how to test
+this adequately, see [[!debbug 466055]]. -- Brian May
+
+---
+
+I think [[!cpan Crypt::SSLeay]] already supports checking the certificate. The trick
+is to get [[!cpan LWP::UserAgent]], which is used by [[!cpan LWPx::ParanoidAgent]] to
+enable this checking.
+
+I think the trick is to set one of the the following environment variables before retrieving
+the data:
+
+$ENV{HTTPS\_CA\_DIR} = "/etc/ssl/certs/";
+$ENV{HTTPS\_CA\_FILE} = "/etc/ssl/certs/file.pem";
+
+Unfortunately I get weird results if the certificate verification fails, see [[!debbug 503440]].
+It still seems to work though, regardless.
+
+-- Brian May
--- /dev/null
+When using the [[plugins/htmltidy]] plugin (and possibly in other circumstances), ikiwiki sometimes creates more `</p>` tags than `<p>` tags, causing unbalanced markup. I've previously noticed unbalanced tags when a `\[[!map]]` matches no pages. This is part of the reason I developed [[plugins/htmlbalance]].
+
+This is particularly noticeable if htmltidy is enabled when building the docwiki: on the 'contrib' plugin pages, the title becomes `foo </p> (third-party plugin)` (with the angle-brackets escaped - it seems the text gets sanitized but is then escaped anyway).
+
+I believe that this snippet in `IkiWiki.pm` might be the reason for the imbalance:
+
+ if ($oneline) {
+ # hack to get rid of enclosing junk added by markdown
+ # and other htmlizers
+ $content=~s/^<p>//i;
+ $content=~s/<\/p>$//i;
+ chomp $content;
+ }
+
+The fact that HTML in a `\[[!meta title]]` is added but then escaped might indicate that some other bug is involved.
--- /dev/null
+I have several complaints that users cannot contribute to my ikiwiki instances since they only have OpenID logins that support OpenID2. E.g. Yahoo!'s OpenID only supports 2.0+
+
+This is not the fault of ikiwiki, though the problem lies within the [perl openid consumer](http://packages.qa.debian.org/libn/libnet-openid-consumer-perl.html) in Debian which is a 1.x implementation AFAIK.
+
+I've contacted JanRain who have pointed me to:
+
+* [OpenID4Perl](http://code.sxip.com/openid4perl/)
+* Some [work](http://code.sixapart.com/svn/openid/trunk/perl/) by David Recordon
+
+However both Perl OpenID 2.x implementations have not been released and are incomplete implementations. :(
+
+> Both of the projects referenced above have since been released.
+> Net::OpenID::Consumer 0.x in Debian is indeed only an OpenID 1
+> implementation. However, Net::OpenID::Consumer 1.x claims to be
+> an OpenID 2 implementation (it's the second of the projects
+> above). I've filed a bug in Debian asking for the package to be
+> updated. --[[smcv]]
+
+> Net::OpenID::Consumer 1.x is now in Debian unstable --[[dom]]
+
+> I've tested with yahoo, and it works with the updated module. Sweet and
+> [[done]] --[[Joey]]
--- /dev/null
+Current git :
+
+ $ perl -c IkiWiki/Plugin/aggregate.pm
+ syntax error at IkiWiki/Plugin/aggregate.pm line 427, near "24;"
+ IkiWiki/Plugin/aggregate.pm had compilation errors.
+
+This prevents a Debian package build (due to `t/syntax.t`).
+
+Not knowing the units being used, I don't know where to add the missing parenthesis.
+
+[[done]]
--- /dev/null
+If wikilinks are put in an external table file, those links are not seen at
+scan time, and so ikiwiki does not know to update the page containing the
+table when the pages the links point to change (are added, removed, etc).
+
+There seem only two solutions to that bug -- either really make wikilinks
+in an external table file not work (probably by escaping them),
+or run the preprocess code also in scan (expensive!). --[[Joey]]
+
+[[done]]
--- /dev/null
+It may be that I'm simply misunderstanding something, but what is the rationale
+for having `tagged()` also match normal wikilinks?
+
+> It simply hasn't been implemented yet -- see the answer in
+> [[todo/tag_pagespec_function]]. Tags and wikilinks share the same
+> underlying implementation, although ab reasonable expectation is that
+> they are kept separate. --Ivan Z.
+
+The following situation. I have `tagbase => 'tag'`. On some pages, scattered
+over the whole wiki, I use `\[[!tag open_issue_gdb]]` to declare that this page
+contains information about an open issue with GDB. Then, I have a page
+`/tag/open_issues_gdb.mdwn` that essentially contains `\[[!map
+pages="tagged(open_issue_gdb)"]]`. So far, so good: this page indeed does list
+all pages that are tagged like this. But now, when I add in `/gdb.mdwn` a link
+to this page, like `\[[Open Issues|tag/open_issue_gdb]]`, then `/gdb.mdwn`
+itself shows up in the map on `tag/open_issues_gdb.mdwn`. In my understanding
+this is due to the wikilink being equal to a `\[[!tag ...]]`. What's the
+rationale on this, or what am I doing wrong, and how to achieve what I want?
+
+--[[tschwinge]]
+
+> What you are doing "wrong" is putting non-tag pages (i.e.
+> `/tag/open_issues_gdb.mdwn`) under your tagbase. The rationale for
+> implementing tag as it has been, I think, is one of simplicity and
+> conciseness. -- [[Jon]]
+
+>> No, he has no pages under tagbase that aren't tags. This bug
+>> is valid. [[todo/matching_different_kinds_of_links]] is probably
+>> how it will eventually be solved. --[[Joey]]
+
+> And this is an illustration why a clean work-around (without changing the software) is not possible: while thinking about [[todo/matching_different_kinds_of_links]], I thought one could work around the problem by simply explicitly including the kind of the relation into the link target (like the tagbase in tags), and by having a separate page without the "tagbase" to link to when one wants simply to refer to the tag without tagging. But this won't work: one has to at least once refer to the real tag page if one wants to talk about it, and this reference will count as tagging (unwanted). --Ivan Z.
+
+> But well, perhaps there is a workaround without introducing different kinds of links. One could modify the [[tag plugin|plugins/tag]] so that it adds 2 links to a page: for tagging -- `tagbase/TAG`, and for navigation -- `tagdescription/TAG` (displayed at the bottom). Then the `tagdescription/TAG` page would hold whatever list one wishes (with `tagged(TAG)` in the pagespec), and whenever one wants to merely refer to the tag, one should link to `tagdescription/TAG`--this link won't count as tagging. So, `tagbase/TAG` would become completely auxiliary (internal) link targets for ikiwiki, the users would edit or link to only `tagdescription/TAG`. --Ivan Z.
--- /dev/null
+I think there might be an issue in the backlinks calculation in ikiwiki 3.04.
+
+I've just migrated to 3.04. In doing so, the following pagespec
+
+> "log/* and !link(tag/aggregation) and !link(tag/draft) and !*/Discussion"
+
+...started matching pages which contained
+
+> \[\[!template draft\]\]
+
+The page templates/draft.mdwn contains (amongst some markup)
+
+> \[\[!tag draft \]\]
+
+Prior to migration, the pagespec definitely took effect post-transclusion.
+
+An example: <http://jmtd.net/log/too_much_debconf_a_bad_thing/> contains the
+template inclusion, which can be seen to have worked due to markup at the
+bottom of the page. It even includes a "Tags: draft" link at the bottom.
+
+Strangely, <http://jmtd.net/tag/draft/> does not contain backlinks to pages
+which are tagged using the procedure above.
+
+After the first rebuild, it's broken, after a subsequent refresh, it is fixed.
+I've reproduced this twice (but assumed I'd done something wrong the first
+time, so went ahead and migrated live, spamming planet debian in the process
+:(). I will try and put together a testcase. -- [[users/Jon]], 2009/02/17
+
+> Looks like the same problem as
+> [[cannot_reliably_use_meta_in_template]]. AFAIK, this has never worked
+> reliably, although the linked page has a simple, though potentially
+> expensive fix. --[[Joey]]
+
+> fix made, [[done]] --[[Joey]]
Already existing tags, corresponding to pages like tags/foo.html work just
fine.
-If I add to a page a tag which is not existing (e.g. with [[tag newtag]])
+If I add to a page a tag which is not existing (e.g. with [[!tag newtag]])
the just modified page will have a link which point to tags/newtag. This is
in theory correct, but in practice leads to creating a tags/newtag subpage
of the page I'm editing, while my tagbase is supposed to be relative to the
> from the list when creating a new page..
>
> --[[Joey]]
+
+> And, this is [[done]], creating tags with tagbase will put them under the
+> tagbase, unless the tag name starts with "/". --[[Joey]]
> even in 5.8. See also: [[prune_causing_taint_mode_failures]],
> [[Insecure_dependency_in_mkdir]],
> [[Insecure_dependency_in_eval_while_running_with_-T_switch]],
-> and especially [[debbug 411786]]
+> and especially [[!debbug 411786]]
>
> The last of those was the last straw for me, and I disabled taint
> checking in the debian package. You can do the same by building ikiwiki
filter => sub {
my $text_ref = shift;
@@ -857,6 +856,7 @@
- } #}}}
+ }
- sub template ($;@) { #{{{
+ sub template ($;@) {
+ require HTML::Template;
HTML::Template->new(template_params(@_));
- } #}}}
+ }
**That** gave me:
Other than ikiwiki.in, am I missing something here?
->> I think this is [[debbug 425891]]. I have sent there a patch that incorporates the original
+>> I think this is [[!debbug 425891]]. I have sent there a patch that incorporates the original
>> author's two diffs but has a more correct solution to the first problem described
>> above. -- Thomas, 2007-06-26
--[[PatrickWinnertz]]
-[[tag done]]
+[[!tag done]]
0x92 is "single quote" in the evil windows default codepage. It would be nice to handle this gracefully and not abort ikiwiki at this point, or alternatively, die fatally but mention which input page caused the error.
-Interestingly enough, in my case, the input file has several other bad windows characters (0xFC, u-umlaut) which have not caused ikiwiki to abort. ikiwiki version 2.50. -- [[JonDowland]]
+Interestingly enough, in my case, the input file has several other bad windows characters (0xFC, u-umlaut) which have not caused ikiwiki to abort. ikiwiki version 2.50. -- [[users/Jon]]
> Fixed in git. [[done]] --[[Joey]]
--- /dev/null
+When the meta plugin is enabled, use of the title() predicate in a [[PageSpec]] fails with "Undefined subroutine &IkiWiki::Plugin::meta::pagetitle called". The [[patch]] is to replace "pagetitle" with "IkiWiki::pagetitle" in the meta plugin, as in [this git commit](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=commit;h=1f26a1bf1655b1d0223b24ba1db70579a3774eb1) (git://git.debian.org/git/users/smcv/ikiwiki.git, branch=master, commit=1f26a).
+
+[[done]] thanks!
--- /dev/null
+The [[plugins/toggle]] plugin has no effect when viewed on the Safari web browser.
+
+All toggles appear open all the time.
+
+I don't know if this is true for other webkit browsers (the new Konqueror, the iPhone, etc).
+I'm currently testing in the Safari nightly builds, but I've seen the bug in the current release
+of Safari too.
+
+Looking at the Safari Web Inspector, it believes there is a parse error on line 47 of the
+[[news]] page. This is the definition of the getElementsByClass(class) function.
+
+ 45 }
+ 46
+ 47 function getElementsByClass(class) {
+ SyntaxError: Parse error
+ 48 var ret = new Array();
+
+> Reproduced in epiphany-webkit on debian.
+>
+> Also noticed something interesting when I opened the page in vim. It
+> highlighted the "class" like a type definition, not a variable. Sure
+> enough, replacing with "c" fixed it.
+>
+> I wonder if webkit is actually in the right here, and using a reseved
+> word like, presumably, "class" as a variable name is not legal. As I try
+> to ignore javascript as much as possible, I can't say. [[done]] --[[Joey]]
+
+>> I also started having a look at this. I found the same issue with the
+>> the variable 'class'. I'm not a javascript guru so I looked on the web
+>> at other implementations of getElementsByClass() and noticed some
+>> things that we might use. I took a bunch of different ideas and came
+>> up with this:
+
+ function getElementsByClass(cls, node, tag) {
+ if (document.getElementsByClass)
+ return document.getElementsByClass(cls, node, tag);
+ if (! node) node = document;
+ if (! tag) tag = '*';
+ var ret = new Array();
+ var pattern = new RegExp("(^|\\s)"+cls+"(\\s|$)");
+ var els = node.getElementsByTagName(tag);
+ for (i = 0; i < els.length; i++) {
+ if ( pattern.test(els[i].className) ) {
+ ret.push(els[i]);
+ }
+ }
+ return ret;
+ }
+
+>> Most of the changes are minor, except that this one will use the
+>> built in function if it is available. That is likely to be significantly
+>> faster. Adding the extra parameters doesn't cause a problem --
+>> they're filled in with useful defaults.
+
+>> I don't know if it is worth making this change, but it is there if you want it.
+
+>>> Well, it seems to work. Although god only knows about IE. Suppose I
+>>> might as well.. --[[Joey]]
--- /dev/null
+When applying my usual copyright and licensing header to a [[plugins/txt]]
+page, garbled output is created.
+
+Here is the header:
+
+ \[[meta copyright="Copyright © 2001, 2002, 2003, 2004, 2005, 2008 Free
+ Software Foundation, Inc."]]
+
+ \[[meta license="""[[toggle id="license" text="GFDL 1.2+"]][[toggleable
+ id="license" text="Permission is granted to copy, distribute and/or modify
+ this document under the terms of the GNU Free Documentation License,
+ Version 1.2 or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled
+ [[GNU_Free_Documentation_License|/fdl]]."]]"""]]
+
+--[[tschwinge]]
+
+> [[done]], made it less zealous about encoding html entities. --[[Joey]]
--- /dev/null
+skeleton.pm.example contains the typo "sessionncgi" when defining a sub, which means the skeleton plugin won't work as a session CGI action as-is. [My repository has a patch on the 'trivia' branch](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=commitdiff;h=72ffc85d). --[[smcv]]
+
+[[!tag patch]]
+
+[[done]]
> alone. If you feel the other things you brought up are bugs, please talk
> to the markdown maintainer. --[[Joey]]
-[[tag done]]
+[[!tag done]]
If a file in the srcdir is removed, exposing a file in the underlaydir,
-ikiwiki will not notice the change and rebuild it until the file in the
-underlaydir gets a mtime newer than the mtime the removed file had.
-
-Relatedly, if there are two files with different extensions that build a
-page with the same name, in a directory, ikiwiki will update the page
-whenever either changes, using the changed one as the source. But if that
-most recently changed one is removed, it won't rebuild the page using the
-older one as the source.
+ikiwiki will notice the removal and delete the page from the destdir. The
+page from the underlay will not be built. (However, it will be if the wiki
+gets rebuilt.)
--- /dev/null
+I spent hours trying to understand why my wiki suddenly refused me to log in (using passwordauth).
+The failure message was always: `login failed, perhaps you need to turn on cookies?`
+
+Inspecting the cookie information (thanks to Iceweasel's webdeveloper add-on), I realized there were some weird-looking encoded chars in the cookie name.
+
+Replacing "·" with "-" in `wikiname` fixed this login issue.
+
+> Hmm, Recai sent me a patch a long time ago to handle utf-8 here by encoding
+> the wikiname. But it doesn't seem to work, somehow the encoded utf-8
+> value still doesn't make it through. (CGI::Session seems to have underermined utf-8
+> issues too.) Seems like I will have to possibly break some sessions and
+> entity-encode the wikiname in the cookie.. [[done]]. --[[Joey]]
+
+>> I confirm it fixes the bug for me. --[[intrigeri]]
+
+(BTW, such a char was replaced by -I don't remember what encoding thingie- in my setup file, when running `ikiwiki-transition setupformat`.)
+
+> Thanks for the heads up, fixed that too. --[[Joey]]
+
+>> I confirm it fixes the bug for me. --[[intrigeri]]
--- /dev/null
+it appears that unicode characters in the title that are unicode letters are spared the __ filename encoding but instead saved in their utf8 encoding. (correct me if i'm wrong; didn't find the code that does this.) -- see below for examples.
+
+> Filenames can have any alphanumerics in them without the __ escaping.
+> Your locale determines whether various unicode characters are considered
+> alphanumeric. In other words, it just looks at the [[:alpha:]] character
+> class, whatever your locale defines it to be. --[[Joey]]
+
+this is not a problem per se, but (at least with git backend) the recent changes missinterpret the file name character set (it seems to read the filenames as latin1) and both display wrong titles and create broken links.
+
+the problem can be shown with an auto-setup'd ikiwiki without cgi when manually creating utf8 encoded filenames and running ikiwiki with LANG=en_GB.UTF-8 .
+
+> Encoding issue, I figured out a fix. [[done]] --[[Joey]]
+
+>> the link text works now, but the link goes to
+>> `ikiwiki.cgi?page=uml%C3%A4ute&do=recentchanges_link`, which fails with
+>> "missing page". it seems that bestlink can't handle utf8 encoded texts. (the
+>> same happens, by the way, when using meta-redir to a page with high bytes in
+>> the name.)
+>>
+>>> The problem is that all cgi inputs have to be explicitly decoded to
+>>> utf-8, which I've now done for `recentchange_link`.
+>>>> thanks a lot, i think that closed the bug.
+>>>
+>>> I cannot, however, reproduce a problem with meta redir. Here it
+>>> generated the following html, which redirected the browser ok:
+>>> <meta http-equiv="refresh" content="0; URL=./../â/" />
+>>>> sorry, my fault -- it was the blank which needed to be replaced by an
+>>>> underscore, not the high byte character
+>>
+>> update: i've had a look at the git options; you could run git with '-z' (NUL
+>> termination) in the `git_commit_info` function; this would require some
+>> changes in `parse_diff_tree`, but otherwise completely eliminate the
+>> problems with git escaping.
+>>
+>>> If you would like to develop a patch to that effect, I'd be glad to
+>>> drop the current nasty code.
+>>>> i'll have a look, but i'm afraid that's above my current perl skills.
+>>>> --[[chrysn]]
--- /dev/null
+Background: some po translations (amongst which `fr.po`) translate "discussion" to an upper-cased word (in French: "Discussion").
+By the way, this is wished e.g. in German, where such a noun has to be written with an upper-cased "D", but I can not see
+the logic behind the added "D" in French.
+
+Anyway, this gettext-translated word is used to name the discussion pages, as `$discussionlink` in `Render.pm` is
+built from `gettext("discussion")`. In the same piece of code, a case-sensitive regexp that tests wether the page
+being rendered is a discussion page is case-sensitive.
+
+On the other hand, new discussion pages are created with a name built from `gettext("Discussion")` (please note the upper-cased
+"D"). Such a new page name seems to be automagically downcased.
+
+This leads to newly created discussion pages not being recognized as discussion pages by the
+`$page !~ /.*\/\Q$discussionlink\E$/` regexp, so that then end with an unwanted discussion link.
+
+A simple fix that seems to work is to make this regexp case-insensitive:
+
+ git diff IkiWiki/Render.pm
+ diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
+ index adae9f0..093c25b 100644
+ --- a/IkiWiki/Render.pm
+ +++ b/IkiWiki/Render.pm
+ @@ -77,7 +77,7 @@ sub genpage ($$) {
+ }
+ if ($config{discussion}) {
+ my $discussionlink=gettext("discussion");
+ - if ($page !~ /.*\/\Q$discussionlink\E$/ &&
+ + if ($page !~ /.*\/\Q$discussionlink\E$/i &&
+ (length $config{cgiurl} ||
+ exists $links{$page."/".$discussionlink})) {
+ $template->param(discussionlink => htmllink($page, $page, gettext("Discussion"), noimageinline => 1, forcesubpage => 1));
+
+But the best way would be to avoid assuming implicitely that translators will translate "discussion" and "Discussion" the same way.
+
+> [[done]] --[[Joey]]
+
+[[!tag patch]]
--- /dev/null
+When I click on a linked username for commits on the recentchanges page (on
+the live ikiwiki.info) I get a link such as
+<http://ikiwiki.info/ikiwiki.cgi?page=users%2Fjoey&do=recentchanges_link>
+which returns something like
+
+ <a href="http://ikiwiki.info">ikiwiki</a>/ Error
+ <p class="error">Error: unknown do parameter
+
+-- [[Jon]]
+
+> That was fixed in 3.04 but ikiwiki.info had not been upgraded to it yet.
+> [[done]] --[[Joey]]
--- /dev/null
+My web server runs in a chroot jail. This makes things interesting because the paths are slightly different depending on whether you are inside or outside the chroot.
+
+To override an incorrectly guessed path, I set setupconf in the .setup file. I also set allow_symlinks_before_srcdir=>1. However, when I tried websetup, the setup file was correctly changed but these important settings disappeared. This seems like a bug.
+
+> I don't know what "setupconf" is. This is the first mention of it in the
+> ikiwiki source tree.
+>
+> I've fixed the `allow_symlinks_before_srcdir` issue. --[[Joey]]
+
+I meant setupfile as in IkiWiki::Setup::dump($config{setupfile}) from IkiWiki/Plugin/websetup.pm
+
+Sorry for the confusion.
+
+> Ok, that's an internal setting that I never envisioned someone digging
+> out and setting in their setup file. It could be made an exported config
+> option, but then every generated setup file will have this setting in it,
+> which will be at best redundant.
+>
+> Can you find another solution, such as a symlink, for your special case?
+
+I see your point. [[done]]
-Wiki formatting between `\[[toc ]]` and an inline fails to render. The
+Wiki formatting between `\[[!toc ]]` and an inline fails to render. The
problem does not seem to trigger if the inline uses the titlepage template,
or if it doesn't match any pages. See example below; also reproducible
with a single-file wiki containing the text below, rendered via `ikiwiki
--plugin toc`.
-> This is [[debbug 421843]], and I suspect it affects certian other plugins
+> This is [[!debbug 421843]], and I suspect it affects certian other plugins
> that also use empty divs as placeholders. It's fixed in markdown 1.0.2 b7
> (available in debian experimental). So I'll [[close|done]] this as it's
> not really an ikiwiki bug. --[[Joey]]
-[[toc ]]
+[[!toc ]]
**not bold**
[not a link](http://ikiwiki.info)
-[[inline pages="news/*" description="Sparse News" show=1 feeds=no]]
+[[!inline pages="news/*" description="Sparse News" show=1 feeds=no]]
**bold**
In [[ikiwiki/markdown]] syntax, none of the other special characters get processed
inside a code block. However, in ikiwiki, [[wiki_links|ikiwiki/wikilink]] and
-[[preprocessor_directives|ikiwiki/preprocessordirective]] still get processed
+[[preprocessor_directives|ikiwiki/directive]] still get processed
inside a code block, requiring additional escaping. For example, `[links
don't work](#here)`, but `a [[ikiwiki/wikilink]] becomes HTML`. --[[JoshTriplett]]
> there should give some strong hints how to fix this bug, though I haven't
> tried to apply the method yet. --[[Joey]]
-[[debbug 487397]]
+[[!debbug 487397]]
I try to create wikilink in table. But it does not work. Here is example:
- \[[table class=table1 data="""
+ \[[!table class=table1 data="""
\[[wikilink_test|index]]
\[[wikilink_test\|index]]
[wikilink test](/servers/webmail1)
Trying to report this I found something weird. I changed in the example [[ with || because wiki renders something wrongly. You can see what I tried originally here:
- \[[table class=table1 data="""
+ \[[!table class=table1 data="""
\[[wikilink_test|servers/webmail1]]
\[[wikilink_test|servers/webmail1]]
[wikilink test](/servers/webmail1)
--- /dev/null
+## Markdown or CGI error prevents web-based editing
+
+I have a working ikiwiki configuration with an SVN backend, running on Ubuntu 7.10, Apache 2.2.4. I'm using Perl 5.8.8, however, I had to use Text::Markdown 1.0.5 from CPAN instead of the latest because I had the same issue as someone [here](http://ikiwiki.info/index/discussion/) (Namely I was getting this error until I used the old Markdown version: "*** glibc detected *** double free or corruption (!prev): 0x0922e478 ***
+").
+
+> aside: that might have been related to [Text::Markdown bug #37297](http://rt.cpan.org/Public/Bug/Display.html?id=37297).
+> --ChapmanFlack 9Jul2008
+
+CGI seems to be working at least partly - the History and Recent Changes pages both work. However, if I attempt to edit or create a page, I get this error:
+ Error: Failed to load plugin IkiWiki::Plugin::mdwn: Can't locate IkiWiki/Plugin/mdwn.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.8.8 /usr/local/share/perl/5.8.8 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl .) at (eval 6) line 2. BEGIN failed--compilation aborted at (eval 6) line 2.
+
+Since ikiwiki builds, it has to be finding Markdown at build time, right? What am I doing wrong here? I would appreciate a point in the right direction. Thanks. --mrled
+
+> Ikiwiki is failing to find `IkiWiki/Plugin/mdwn.pm` which is a plugin included in ikiwiki itself.
+> So, that file must not have been installed in any of the directories in the @INC search path listed.
+> Either fix the installation so ikiwiki's perl modules are installed in one of the standard locations,
+> or you could use the `libdir` setting in the setup file to point ikiwiki
+> at the directory the perl modules are installed. --[[Joey]]
+
+>> Ah hah! That helped... once I knew that it was ikiwiki's internal thing, I was able to figure out that it was a permissions issue. For the record, I didn't change permissions or the default install prefix of /usr/local (well, at least not on purpose). Thanks for your help. --mrled
+
+>>> Interesting.. so just a permissions problem of some sort that prevented the cgi from seeing the modules that were there in-path? --[[Joey]]
[CIA](http://cia.navi.cx), and IRC, and respond in a timely fashion.
You could also drop by the IRC channel `#ikiwiki` on
-[OFTC](http://www.oftc.net/) (`irc.oftc.net`).
+[OFTC](http://www.oftc.net/) (`irc.oftc.net`), or use the
+[identi.ca ikiwiki group](http://identi.ca/group/ikiwiki).
--- /dev/null
+Do you have an existing wiki or blog using other software, and would like
+to convert it to ikiwiki? Various tools and techniques have been developed
+to handle such conversions.
+
+* [[tips/convert_mediawiki_to_ikiwiki]]
+* [[tips/convert_MoinMoin_and_TWiki_to_ikiwiki]]
+* [[tips/convert_blogger_blogs_to_ikiwiki]]
-[[meta title="CSS"]]
+[[!meta title="CSS"]]
## Using CSS with ikiwiki
-[[meta title="CSS Market"]]
+[[!meta title="CSS Market"]]
-User contributed stylesheet files for ikiwiki. Feel free to add your own
-stylesheets here. (Upload as wiki pages; wiki gnomes will convert them to css
-files..)
+User contributed stylesheet files for ikiwiki. Unless otherwise noted,
+these style sheets can be installed by copying them into your wiki's source
+dir with a filename of `local.css`.
+
+Feel free to add your own stylesheets here. (Upload as wiki pages; wiki
+gnomes will convert them to css files..)
* **[[css_market/zack.css]]**, contributed by [[StefanoZacchiroli]],
customized mostly for *blogging purposes*, can be seen in action on
- [zack's blog](http://www.bononia.it/~zack/blog/)
- [[meta stylesheet="zack"]]
+ [zack's blog](http://upsilon.cc/~zack/blog/)
+ [[!meta stylesheet="zack"]]
* **[[css_market/kirkambar.css]]**, contributed by [[Roktas]]. This far from perfect
stylesheet follows a [Gitweb](http://www.kernel.org/git/?p=git/git.git;a=tree;f=gitweb)
like theme, so it may provide a consistent look'n feel along with the [[rcs/git]] backend. ;-)
You can see it in action on [kirkambar](http://kirkambar.net/) (Turkish content).
- [[meta stylesheet="kirkambar"]]
+ [[!meta stylesheet="kirkambar"]]
* **[[css_market/embeddedmoose.css]]**, contributed by [[JoshTriplett]].
Designed for [Embedded Moose](http://embeddedmoose.com). Some ideas from the
Debian lighttpd index.html page.
- [[meta stylesheet="embeddedmoose"]]
-
-* **Refresh**, contributed by [[FredericLespez]]. Adapted from a free template
- designed by [styleshout](http://www.styleshout.com).
- You can see it [here](http://fred.ccheznous.org). You can download the local.css file and
- the modified templates [here](http://fred.ccheznous.org/refresh_20060602.tgz).
- * You'll find a updated version of these templates [here](http://www.der-winnie.de/~winnie/configs/ikiwiki-templates.tar.gz).
- These templates are known to work with ikiwiki 2.31, and since I'll install always the newest one on my server I'll will update them on a regular basis.
-
+ [[!meta stylesheet="embeddedmoose"]]
* **[[02_Template.css]]**, contributed and adapted by [maxx](http://martin.wuertele.net/), [original](http://www.openwebdesign.org/viewdesign.phtml?id=3057)
designed by [jarico](http://www.openwebdesign.org/userinfo.phtml?user=jcarico)
**[[css_market/02_Template.tmpl]]**. If you prefer
[my header image](http://martin.wuertele.net/images/header.png) you can
use it under the terms of the MIT License (see png comment).
- [[meta stylesheet="02_Template"]]
+ [[!meta stylesheet="02_Template"]]
* **[[css_market/cstamas.css]]**, contributed by [[cstamas]].
This one is based on embeddedmoose, however it is slightly different now.
[My webpage's](http://users.itk.ppke.hu/~cstamas/tag/english) is not the same.
You can grab some pictures used as background patterns from there.
- [[meta stylesheet="cstamas"]]
+ [[!meta stylesheet="cstamas"]]
* **[[css_market/bma.css]]**, contributed by [bma](http://subvert.org.uk/~bma/).
Not quite the same as I use on my site, since that has slightly modified
templates.
- [[meta stylesheet="bma"]]
+ [[!meta stylesheet="bma"]]
+
+* **[blankoblues.css][1]**, contributed by [[Blanko]]. Can be seen on [Blankoblues Demo][2]. Local.css and templates available [here][3].
+
+* **[contraste.css][4]**, contributed by [[Blanko]]. Can be seen on [Contraste Demo][5]. Local.css and templates available [here][6].
+
+* **[[css_market/actiontabs.css]]**, contributed by [[svend]]. This style sheet displays
+ the action list (Edit, RecentChanges, etc.) as tabs.
+ [[!meta stylesheet="actiontabs"]]
If your web browser allows selecting between multiple stylesheets, this
page can be viewed using many of the stylesheets above. For example, if
using Epiphany with the Select Stylesheet extension enabled, use View ->
Style. In Firefox or Iceweasel, use View -> Page Style.
+
+<!-- Page links -->
+
+ [1]: http://blankoworld.homelinux.com/demo/ikiwiki/blankoblues/src/local.css (Download Blankoblues CSS)
+ [2]: http://blankoworld.homelinux.com/demo/ikiwiki/blankoblues/htdocs/ (Take a tour on Blankoblues Demo)
+ [3]: http://blankoworld.homelinux.com/demo/ikiwiki/blankoblues/blankoblues.tar.gz (Download local.css and templates for Blankoblues theme)
+ [4]: http://blankoworld.homelinux.com/demo/ikiwiki/contraste/src/local.css (Download Contraste CSS)
+ [5]: http://blankoworld.homelinux.com/demo/ikiwiki/contraste/htdocs/ (Take a tour on Contraste Demo)
+ [6]: http://blankoworld.homelinux.com/demo/ikiwiki/contraste/contraste.tar.gz (Download local.css and templates for Contraste theme)
--- /dev/null
+/* ikiwiki local style sheet */
+
+/* Add local styling here, instead of modifying style.css. */
+
+a {
+ text-decoration: none;
+ color: #005a9c;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+
+hr {
+ border-style: none;
+ background-color: #999;
+ height: 1px;
+}
+
+code, pre {
+ background: #eee;
+}
+
+pre {
+ padding: .5em;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: sans-serif;
+ color: black;
+ background: white;
+}
+
+.pageheader {
+ margin: 0;
+ padding: 1em 2em 0 2em;
+ background: #eee;
+ border-color: #999;
+ border-style: none none solid none;
+ border-width: 1px;
+}
+
+.header {
+ font-size: 100%;
+ font-weight: normal;
+}
+
+.title {
+ display: block;
+ margin-top: .2em;
+ font: 140% sans-serif;
+ text-transform: capitalize;
+}
+
+.actions {
+ text-align: right;
+ padding: 0;
+}
+
+#content, #comments, #footer {
+ margin: 1em 2em;
+}
+
+#pageinfo {
+ border-color: #999;
+}
+
+.inlinepage {
+ margin: .4em 0;
+ padding: .4em 0;
+ border-style: none;
+ border-top: 1px solid #aaa;
+}
+
+.inlineheader {
+ font-size: 120%;
+ font-weight: normal;
+}
+
+h1 { font: 120% sans-serif }
+h2 { font: bold 100% sans-serif }
+h3 { font: italic 100% sans-serif }
+h4, h5, h6 { font: small-caps 100% sans-serif }
+
+/* Smaller headings for inline pages */
+.inlinepage h1 { font-size: 110% }
+.inlinepage h2 { font-size: 100% }
+.inlinepage h3 { font-size: 100% }
+
+.pageheader .actions ul {
+ border-style: none
+}
+
+.actions ul {
+ font-size: 75%;
+ padding: 0;
+ border-style: none;
+}
+
+.actions ul li a {
+ text-decoration: none;
+}
+
+.actions ul li {
+ margin: 0;
+ padding: .1em .5em 0 .5em;
+ background: white;
+ border-color: #999;
+ border-style: solid solid none solid;
+ border-width: 1px;
+}
+
+div.recentchanges {
+ border-style: none;
+}
+
+.pagecloud {
+ width: auto;
+}
--- /dev/null
+What is the correct way to install the .tmpl files? -- [[JosephTurian]]
+
+> For themes that need them, you can set `templatedir` to some directory in
+> your setup file, and put the templates there. Or install directly overtop
+> ikiwiki's standard templates (in, eg `/usr/share/ikiwiki/templates`)
+> --[[Joey]]
+
+----
+
+How can I update a .css file uploaded to the CSS market?
+My CSS has been updated to address comments (for the comments plugin), but I cannot find a way to update zack.css.
+The most recent version is always available at: <http://git.upsilon.cc/cgi-bin/gitweb.cgi?p=zack-homepage.git;a=blob_plain;f=local.css;hb=HEAD>
+
+-- [[StefanoZacchiroli]]
+
+> Just letting me know about the change works -- updated. --[[Joey]]
+
+----
+
+Added small changes to embeddedmoose.css to work with ikiwiki 3.x. Figured here is as good as any until Josh can review and update if he so chooses: <http://bosboot.org/tb-embeddedmoose.css>. It removes annoying borders around the header and footer. -- [[TimBosse]]
+
+-----
+
+I removed this from the list since both places to download it are broken.
+--[[Joey]]
+
+* **Refresh**, contributed by [[FredericLespez]]. Adapted from a free template
+ designed by [styleshout](http://www.styleshout.com).
+ You can see it [here](http://fred.ccheznous.org). You can download the local.css file and
+ the modified templates [here](http://fred.ccheznous.org/refresh_20060602.tgz).
+
+ * This link (above) seems to deliver an empty tarball.
+
+ * You'll find a updated version of these templates [here](http://www.der-winnie.de/~winnie/configs/ikiwiki-templates.tar.gz).
+ These templates are known to work with ikiwiki 2.31, and since I'll install always the newest one on my server I'll will update them on a regular basis.
+ * (This link appears to be broken?)
+
*/
body {
- font-family: sans;
- width: 760px;
- margin-left: 20px;
+ font-family: sans-serif;
+ font-size: medium;
}
+h1, h2, h3, h4 {
+ font-weight: normal;
+}
+h1 { font-size: 140%; }
+h2 { font-size: 120%; }
+h3 { font-size: 110%; }
+h4 { font-size: 105% }
-div#content {
- font-size: 11pt;
+a { text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+.flow {
+ float: right;
+ margin-left: 10px;
+ margin-bottom: 10px;
+ text-align: center;
}
-.header span {
- font-size: 14pt;
- font-weight: normal;
+.attrib-caption {
+ font-size: xx-small;
+ font-style: italic;
}
-div.actions ul {
- font-size: 10pt;
+input {
+ border: solid 1px;
+ border-color: #aaa;
}
-h1 {
- font-weight: normal;
- font-size: 17pt;
+.header { font-weight: normal; }
+
+.selflink { text-decoration: underline; }
+
+.pageheader .actions ul,
+#sitemeta {
+ border-top: solid 1px;
+ border-bottom: solid 1px;
+ font-size: small;
+ border-color: #aaa;
+ background: #eee;
}
-h2 {
- font-weight: normal;
- font-size: 16pt;
+.actions ul {
+ padding: 1px;
+ margin-top: 5px;
}
-h3 {
- font-weight: normal;
- font-size: 15pt;
+#sitemeta {
+ padding: 0;
+ margin-bottom: 5px;
}
-h4 {
- font-weight: normal;
- font-size: 14pt;
+#backlinks,
+.tags {
+ margin-top: 0;
+ margin-bottom: 0;
}
-h5 {
- font-weight: normal;
- font-size: 13pt;
+
+#pageinfo {
+ border: none;
}
-h6 {
- font-weight: normal;
- font-size: 12pt;
+
+#searchform div:before {
+ font-size: small;
+ content: "search:";
+}
+#searchform input {
+ border-top: none;
+ border-bottom: none;
+ vertical-align: bottom;
+ margin-right: 7px;
}
-div.inlinepage > span.header > a {
- float: right;
- display: block;
- font-size: 11pt;
- font-weight: normal;
- margin: 0;
+#sidebar {
+ border: solid;
+ border-width: 1px;
padding: 0;
+ margin-top: 15px;
+ border: 1px solid;
+ border-color: #aaa;
+ background: #eee;
+ width: 16ex;
}
-div.inlinepage > span.header > a:before {
- content: "permalink: ";
- font-size: smaller;
- text-decoration: none;
- font-style: italic;
+#sidebar ul {
+ margin: 0;
+ padding-left: 1em;
+ list-style-type: none;
}
-
-div.inlinepage {
- margin-bottom: 10px;
+#sidebar ul ul {
+ padding-left: 1.5em;
+ font-size: 90%;
}
-div.inlinepage h1 {
- font-weight: normal;
- font-size: 14pt;
+#pageinfo,
+#footer {
margin: 0;
}
-div.inlinepage h2 {
- font-weight: normal;
- font-size: 13pt;
- margin: 0;
+#pageinfo {
+ font-size: small;
}
-div.inlinepage h3 {
- font-weight: normal;
- font-size: 12pt;
+.pagecopyright,
+.pagelicense,
+.pagedate {
margin: 0;
+ display: inline;
}
-div.inlinepage h4 {
- font-weight: normal;
- font-size: 11pt;
- margin: 0;
+#backlinks {
+ margin-top: 5px;
+ margin-bottom: 10px;
+ font-size: larger;
}
-div.inlinepage h5 {
- font-weight: normal;
- font-size: 11pt;
- margin: 0;
+.validation {
+ display: inline;
+ float: right;
}
-div.inlinepage h6 {
- font-weight: normal;
- font-size: 11pt;
- margin: 0;
+
+.pagecloud {
+ margin-left: 5px;
}
-div#blogform {
- padding: 0px 5px;
- margin-bottom: 10px;
+table.identikit tr th {
+ text-align: right;
+ vertical-align: top;
+}
+table.identikit tr th:after {
+ content: ":";
+}
+table.identikit tr td {
+ text-align: left;
+ vertical-align: top;
}
-pre {
- width: 90%;
- font-size: 10pt;
- font-family: monospace;
- background: #e1e1e1;
- margin-left: 4%;
- padding-top: 5px;
- padding-bottom: 5px;
+.doi_logo , .doi_logo a {
+ background: #3965bd;
+ color: white !important;
+ font-size: 80%;
+ text-decoration: none;
+ font-family: times;
+ font-weight: bold;
+ padding: 0px 1px 0px 2px;
}
-.pagecloud {
- width: 25%;
- border-top: 1px solid #aaa;
- border-bottom: 1px solid #aaa;
- background: #eee;
- color: black !important;
+#comments {
+ margin-top: 5ex;
+ border-top: solid 1px;
+ border-color: #aaa;
+ font-size: small;
+}
+
+#comments #feedlink {
+ text-align: right;
+}
+#comments #feedlink:before {
+ content: "comment feeds: ";
+}
+
+.addcomment {
+ padding: 5px;
+ font-style: italic;
+}
+
+.comment {
+ border: none;
+ background-color: #eee;
+ margin: 5px;
+ margin-top: 10px;
+}
+
+.comment-subject {
+ font-style: normal;
}
-.pagecloud a {
- text-decoration: none;
+.comment-header {
+ border-top: solid 1px;
+ border-color: #aaa;
+ text-align: right;
+ font-style: normal;
}
## packages
-If using Debian (since 4.0), or Ubuntu (since 6.10):
-[[template id=note text="""
-Note that Debian 4.0 and especially Ubuntu 6.10 contain older versions of
-ikiwiki, there have been lots of enhancements and bug fixes since those
-versions.
-"""]]
+To install with apt, if using Debian or Ubuntu:
apt-get install ikiwiki
There is a backport of a recent version of ikiwiki for Debian 4.0 at
<http://packages.debian.org/etch-backports/ikiwiki>.
-There is also an unofficial backport of ikiwiki for Ubuntu Gutsy
-and Ubuntu Hardy, provided by Paweł Tęcza,
+Fedora versions 8 and newer have RPMs of ikiwiki available.
+
+There is also an unofficial backport of ikiwiki for Ubuntu Jaunty, provided by
+[[Paweł_Tęcza|users/ptecza]],
at [http://gpa.net.icm.edu.pl/ubuntu/](http://gpa.net.icm.edu.pl/ubuntu/index-en.html).
-Also, FreeBSD has ikiwiki in its
+NetBSD and many other platforms: pkgsrc has an [ikiwiki package](ftp://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/www/ikiwiki/README.html).
+
+FreeBSD has ikiwiki in its
[ports collection](http://www.freshports.org/www/ikiwiki/).
-And Gentoo has an [ebuild](http://bugs.gentoo.org/show_bug.cgi?id=144453) in its bug database.
+Gentoo has an [ebuild](http://bugs.gentoo.org/show_bug.cgi?id=144453) in its bug database.
+
+The [openSUSE Build Service](http://software.opensuse.org/search?baseproject=ALL&p=1&q=ikiwiki) has packages for openSUSE
+
+IkiWiki can be installed [from macports](http://www.macports.org/ports.php?by=name&substr=ikiwiki)
+by running `sudo port install ikiwiki`.
+
+A [PKGBUILD for Arch Linux](http://aur.archlinux.org/packages.php?ID=12284) is in the AUR.
## revision control
This is an [[example_blog|index]]. Just copy the blog subdirectory into
-your wiki to quickly get started blogging with ikiwiki.
+your wiki to quickly get started blogging with ikiwiki.
-Some additional configuration you might want to do:
+Or, run this command to set up a blog with ikiwiki.
+
+ % ikiwiki -setup /etc/ikiwiki/auto-blog.setup
-* Change the name of the blog, by editing `index.mdwn` and changing
- the `title`.
+Some additional configuration you might want to do:
* Make sure to configure ikiwiki to generate RSS or Atom feeds.
* Make sure you have the tag plugin enabled, and tag posts using it. An
example of how to tag a post is:
- \[[tag tags/life]]
+ \[[!tag tags/life]]
+
+* Enable the [[sidebar|plugins/sidebar]] plugin to get a sidebar listing all
+ the categories you've tagged posts with.
+
+* Enable the [[pagestats|plugins/pagestats]] plugin to get a tag cloud
+ to display on the [[index]].
-* Enable the sidebar plugin to get a sidebar listing all the categories
- you've tagged posts with.
+* Enable the [[comments|plugins/comments]] plugin and configure it to
+ enable comments to posts to the blog:
-* Enable the pagestats plugin to get a tag cloud display on the [[index]].
+ comments_pagespec => 'blog/posts/* and !*/Discussion',
-[[meta title="example blog"]]
+[[!pagestats pages="./tags/*"]]
-[[pagestats pages="./tags/*"]]
+Welcome to my blog.
-Welcome to my blog. Have a look at the most recent posts below, or
-browse the tag cloud on the right. An archive of all [[posts]] is also
-available.
+Have a look at the most recent posts below, or browse the tag cloud on the
+right. An archive of all [[posts]] is also available.
-[[inline pages="./posts/* and !*/Discussion" show="10"
-actions=yes rootpage="./posts"]]
+[[!inline pages="./posts/* and !*/Discussion" show="10"
+actions=yes rootpage="posts"]]
----
-This wiki is powered by [ikiwiki](http://ikiwiki.info).
+This blog is powered by [ikiwiki](http://ikiwiki.info).
Here is a full list of posts to my [[blog|index]].
-[[inline pages="./posts/* and !*/Discussion" archive=yes feedshow=10 quick=yes]]
+[[!inline pages="./posts/* and !*/Discussion" archive=yes feedshow=10 quick=yes]]
This is the first post to this example blog. To add new posts, just add
-files to the blog/posts/ subdirectory, or use the web form.
+files to the posts/ subdirectory, or use the web form.
-[[tag tags/tech]]
+[[!tag tags/tech]]
* [[Archive|posts]]
Categories:
-[[map pages="./tags/* and !*/Discussion"]]
+[[!map pages="./tags/* and !*/Discussion"]]
-[[pagestats pages="./tags/*"]]
+[[!pagestats pages="./tags/*"]]
On the right you can see the tag cloud for this blog.
This feed contains pages in the "life" category.
-[[inline pages="link(tags/life) and ./posts/* and !*/Discussion"
+[[!inline pages="link(tags/life) and !*/Discussion"
show="10" actions=yes]]
This feed contains pages in the "tech" category.
-[[inline pages="link(tags/tech) and !*/Discussion" show=10 actions=yes]]
+[[!inline pages="link(tags/tech) and !*/Discussion" show=10 actions=yes]]
This is FooBar's bug list. Link bugs to [[bugs/done]] when done.
-[[inline pages="./bugs/* and !./bugs/done and !link(done)
+[[!inline pages="./bugs/* and !./bugs/done and !link(done)
and !*/Discussion" actions=yes postform=yes show=0]]
recently fixed [[bugs]]
-[[inline pages="./* and link(./done) and !*/Discussion" sort=mtime show=10]]
+[[!inline pages="./* and link(./done) and !*/Discussion" sort=mtime show=10]]
FooBar frequently asked questions.
-[[toc ]]
+[[!toc ]]
## Is this a real program?
FooBar is an amazing example program that does not exist. Use it for all
your example program needs. This is its wiki.
-* [[download]]
+* **[[download]]**
* [[news]]
* [[documentation|doc]]
* [[bugs]]
posted. FooBar users are recommended to subscribe to this page's RSS
feed.
-[[inline pages="./news/* and !*/Discussion" rootpage="news" show="30"]]
+[[!inline pages="./news/* and !*/Discussion" rootpage="news" show="30"]]
<TMPL_VAR news>
</TMPL_IF>
-FooBar <TMPL_VAR version> released with [[toggle text="these changes" id="changelog"]]
-[[toggleable id="changelog" text="""<TMPL_VAR changelog>"""]]
+FooBar <TMPL_VAR version> released with [[!toggle text="these changes" id="changelog"]]
+[[!toggleable id="changelog" text="""<TMPL_VAR changelog>"""]]
An overview of some of ikiwiki's features:
-[[toc ]]
+[[!toc ]]
## Uses a real RCS
Rather than implement its own system for storing page histories etc,
-ikiwiki uses a real Revision Control System. This isn't (just) because we're
-lazy, it's because a real RCS is a good thing to have, and there are
-advantages to using one that are not possible with a standard wiki.
+ikiwiki uses a real [[Revision_Control_System|rcs]]. This isn't (just)
+because we're lazy, it's because a real RCS is a good thing to have, and
+there are advantages to using one that are not possible with a standard
+wiki.
Instead of editing pages in a stupid web form, you can use vim and commit
changes via [[Subversion|rcs/svn]], [[rcs/git]], or any of a number of other
ikiwiki can be run from a [[post-commit]] hook to update your wiki
immediately whenever you commit a change using the RCS.
+It's even possible to securely let
+[[anonymous_users_git_push_changes|tips/untrusted_git_push]]
+to the wiki.
+
Note that ikiwiki does not require a RCS to function. If you want to
run a simple wiki without page history, it can do that too.
by ikiwiki. Markdown understands text formatted as it would be in an email,
and is quite smart about converting it to html. The only additional markup
provided by ikiwiki on top of regular markdown is the [[ikiwiki/WikiLink]] and
-[[ikiwiki/PreprocessorDirective]].
+the [[ikiwiki/directive]].
If you prefer to use some other markup language, ikiwiki allows others to
easily be added by [[plugins]]. For example it also supports traditional
## Blogging
-You can turn any page in the wiki into a [[ikiwiki/blog]]. Pages matching a
+You can turn any page in the wiki into a [[blog]]. Pages matching a
specified [[ikiwiki/PageSpec]] will be displayed as a weblog within the blog
page. And RSS or Atom feeds can be generated to follow the blog.
## [[Plugins]]
-Plugins can be used to add additional features to ikiwiki. The interface
-is quite flexible, allowing plugins to implement additional markup
-languages, register [[ikiwiki/PreProcessorDirective]]s, hook into [[CGI]] mode,
-and more. Most of ikiwiki's features are actually provided by plugins.
-Ikiwiki's backend RCS support is also pluggable, so support for new
-revision control systems can be added to ikiwiki.
+Plugins can be used to add additional features to ikiwiki. The interface is
+quite flexible, allowing plugins to implement additional markup languages,
+register [[directives|ikiwiki/directive]], provide a [[RCS]] backend, hook
+into [[CGI]] mode, and much more. Most of ikiwiki's features are actually
+provided by plugins.
The standard language for ikiwiki plugins is perl, but ikiwiki also supports
[[plugins/write/external]] plugins: Standalone programs that can be written in
Thanks to subpages, every page can easily and automatically have a
/Discussion subpage. By default, these links are included in the
-[[templates]] for each page.
+[[templates]] for each page. If you prefer blog-syle
+[[plugins/comments]], that is available too.
### Edit controls
-Wiki admins can [[lock_pages|page_locking]] so that only other admins can
-edit them. Or a wiki can be set up to allow anyone to edit Discussion
-pages, but only registered users to edit other pages. These are just two
-possibilities, since page edit controls can be changed via plugins.
+Wiki admins can lock pages so that only other admins can edit them. Or a
+wiki can be set up to allow anyone to edit Discussion pages, but only
+registered users to edit other pages. These are just two possibilities,
+since page edit controls can be changed via plugins.
### [[PageHistory]]
ikiwiki can use the xapian search engine to add powerful
full text [[plugins/search]] capabilities to your wiki.
+### Translation via po files
+
+The [[plugins/po]] plugin allows translating individual wiki pages using
+standard `po` files.
+
### [[w3mmode]]
Can be set up so that w3m can be used to browse a wiki and edit pages
## Current topics ##
-[[inline pages="forum/* and !forum/discussion and !forum/*/*"
-actions=yes rootpage="forum" postformtext="Add a new thread titled:" show=0]]
+[[!inline pages="forum/* and !forum/discussion and !forum/*/*"
+archive=yes rootpage="forum" postformtext="Add a new thread titled:" show=0]]
--- /dev/null
+If I set a meta value on a page (lets say \[[!meta author="Adam Shand"]] is there some way to retrieve the value of author and put it somewhere visible on the page? Eg. can I write:
+
+author: $author
+
+I know I can update the raw templates but it'd be nice to be able to do this in the pages them selves.
+
+Cheers,
+Adam.
--- /dev/null
+I'm using ikiwiki to manage my personal wiki. One of the things I'm toying with is storing my grocery list in a wiki. The way I typically grocery-shop is to make one huge master list containing all the items I typically buy in a single cycle. Then, on any given trip, I make a subset list containing only the items I need. I'd like to streamline this process by making the master list a series of checkboxes. Before each trip, I load the list page on my phone, check off all the items I already have, then check off individual items as I get them.
+
+I'm not sure if there's a convenient way of adding checkboxes to wiki pages, and after a bit of thought I decided that "( )" would be a good markup for this. Ideally I'd like to still have access to other markdown conventions so I could, say, organize the list with headings and such when it grows large, so I don't want to create an entirely separate format, or a separate copy of the markdown plugin.
+
+Is there an existing means of, say, adding supersets to wiki markup? I suppose I could use an inline directive that inserts a multisellect HTML element, but I really like ( ). :)
+
+Ideal would be some sort of filter infrastructure. Plugins could register with a larger filter plugin that adds an inline directive. I could then invoke the checkbox filter at the top of my grocery list, and all instances of ( ) would be replaced with HTML. Might also make sense for the individual filters to specify whether or not they're invoked before or after the page template, or perhaps just always invoke them after. *shrug*
+
+Does something like this exist? I'd really like to avoid messing around with raw HTML or an inline for each of 40-50 list items. :)
+
+-- [[Nolan]]
--- /dev/null
+I've just finished an upgrade to 3.141 and am trying to give myself admin rights to play with the new webadmin features. My login is via OpenID but from reading on the wiki I believe that OpenID users should be able to be granted admin rights. However I'm obviously doing something wrong as when I click on the "Preferences" link at the top of the page I don't see any admin features.
+
+My login is: http://adam.shand.net/
+
+In .ikiwiki/userdb I see:
+
+> adam@shand.net
+> email <br>
+> password <br>
+> locked_pages <br>
+> banned <br>
+> 1229722296 <br>
+> regdate <br>
+> http://adam.shand.net/ <br>
+
+And in my config file I have:
+
+> adminuser => [qw{http://adam.shand.net/}],
+
+Any pointers to what I'm doing wrong would be much appreciated.
+
+Thanks,
+Adam.
+
+> This is certianly supposed to work. For example, the admin
+> user on my ikiwikis is `http://joey.kitenet.net/`
+>
+> The only caveat I know of to make it work is that the
+> adminuser openid url has to exactly match the openid url that
+> ikiwiki sees when you log in. Including any trailing slash,
+> and the `http://`. --[[Joey]]
+
+>> Hrm, it's not working. I'm sure I've made a silly mistake somewhere but
+>> I've looked and looked and just can't find it. Any suggestions on where
+>> to look for debugging information would be much appreciated. -- [[Adam]]
+
+>>> Well, you could use this patch to add debugging info about admin
+>>> username comparisons:
+
+<pre>
+diff --git a/IkiWiki/UserInfo.pm b/IkiWiki/UserInfo.pm
+index 0bf100a..77b467a 100644
+--- a/IkiWiki/UserInfo.pm
++++ b/IkiWiki/UserInfo.pm
+@@ -71,6 +71,8 @@ sub userinfo_setall ($$) {
+ sub is_admin ($) {
+ my $user_name=shift;
+
++ print STDERR "is_admin test @{$config{adminuser}} vs $user_name: ".(grep { $_ eq $user_name } @{$config{adminuser}})."\n";
++
+ return grep { $_ eq $user_name } @{$config{adminuser}};
+ }
+
+</pre>
+
+>>>> After applying that change to what is probably
+>>>> `/usr/share/perl5/IkiWiki/UserInfo.pm` on your system,
+>>>> when you go to the preferences page it should log in your web server's
+>>>> error.log, something like this:
+
+ [Wed Jul 08 12:54:35 2009] [error] [client 127.0.1.1] is_admin test http://joey.kitenet.net/ vs http://joey.kitenet.net/: 1
+
+>>>> So you can see if the two usernames/openids match. If the end is "0",
+>>>> they don't match. If nothing is logged, you have not enabled the websetup plugin.
+>>>> If the end if "1" you should see the "Wiki Setup" button, if not the
+>>>> problem is not in determining if you're an admin, but elsewhere..
+>>>> --[[Joey]]
+
+I was being incredibly stupid and missed that websetup is a **plugin** and thus needed to be enabled. Many thanks for your patient assistance, by helping me eliminate the unlikely it eventually led me to the obvious. Cheers. -- [[Adam]]
--- /dev/null
+Hi,
+
+I have successfully installed and set up my first instance of [[ikiwiki]] on my dedicated server. Following [[joey]]'s screencasts made this easy (thank you).
+
+Currently, I have set up the RCS to be git but I do not like this very much. I'd rather want darcs but if I replace rcs settings, it fails.
+
+What should I put in the configuration file to use darcs ?
+
+> Darcs is not yet supported. It's being [[worked_on|todo/darcs]].
+
+> > That's good news for me then ! Thank you.
+
+>>> Better news: It will be in version 2.10. --[[Joey]]
--- /dev/null
+This is similar to the last post in this forum. I want to know exactly how ikiwiki remembers the times associated with pages, especially when using it for blogging, so I know whether I can trust it or not. From that last thread, I think what ikiwiki does is this:
+
+* The created time of a file is when that file was first committed into the versioning repository (in my case git)
+
+ > If `--getctime` it used, yes. In normal operation, when new files
+ > are added, ikiwiki sets the creation time to the ctime of the file
+ > on disk, rather than bothering to ask the VCS. --[[Joey]]
+
+* The modified time of a file is what that file was last updated in the repository
+
+ > Almost right, the modified time is actually taken from the
+ > modification time of the file in disk. --[[Joey]]
+
+And with a blog, by default, the posts are ordered by creation time, although an option can order them by modified time.
+
+Okay. So this should mean that the times are safe if, for example, I delete my working copy and then clone another one from the bare git repository, or otherwise mess up the creation times and mtimes stored as file metadata on the filesystem.
+
+Do I have it right?
+
+> Some VCS, like git, set the file mtimes to the current time
+> when making a new checkout, so they will be lost if you do that.
+> The creation times can be retrived using the `--getctime` option.
+> I suppose it might be nice if there were a `--getmtime` that pulled
+> true modification times out of the VCS, but I haven't found it a big
+> deal in practice for the last modification times to be updated to the
+> current time when rebuilding a wiki like this. --[[Joey]]
+>
+> > Thanks for the clarification. I ran some tests of my own to make sure I understand it right, and I'm satisfied
+> > that the order of posts in my blog can be retrieved from the VCS using the `--getctime` option, at least if I
+> > choose to order my posts by creation time rather than modification time. But I now know that I can't rely on
+> > page modification times in ikiwiki as these can be lost permanently.
+> >
+> > I would suggest that there should at least be a `--getmtime` option like you describe, and perhaps that
+> > `--getctime` and `--getmtime` be _on by default_. In my opinion the creation times and modification times of
+> > pages in ikiwiki are part of the user's content and are important to protect, because the user may be relying
+> > on them, especially if they use blogging or lists of recently modified pages, etc. Right now the modification
+> > times can be lost permanently.
+> >
+> > Is there a typo in the description of `--getctime` in the man page?
+> >
+> > > --getctime
+> > > Pull **last changed time** for each new page out of the revision
+> > > control system. This rarely used option provides a way to get
+> > > the real creation times of items in weblogs, such as when build‐
+> > > ing a wiki from a new Subversion checkout. It is unoptimised and
+> > > quite slow. It is best used with --rebuild, to force ikiwiki to
+> > > get the ctime for all pages.
+> >
+> > Surely it is not the _last changed time_ but the _first seen time_ of each page that is pulled out of the VCS?
+> > If the aim is to get the real creation times of items in weblogs, then the last times that the items were
+> > changed in the VCS is not going to help. -- [[seanh]]
+>>> Typo, fixed. --[[Joey]]
+
+> > > If you want to preserve the date of a page, the best way to do it is to
+> > > use [[ikiwiki/directive/meta]] date="foo". This will survive checkouts,
+> > > VCS migrations, etc. -- [[Jon]]
+> > >
+> > > > That's a good tip Jon. That would also survive renaming a page by renaming its mdwn file, which would
+> > > > normally lose the times also. (And in that case I think both times are irretrievable, even by
+> > > > `--getctime`). I might start using a simple script to make blog posts that creates a file for
+> > > > me, puts today's date in the file as a meta, and opens the file in my editor. -- [[seanh]]
+
+>>>>> I use a script that does that and also sets up templates and tags
+>>>>> for a new item:
+
+ #!/bin/sh
+ set -u
+ set -e
+
+ if [ $# -ne 1 ]; then
+ echo usage: $0 pagename >&2
+ exit 1
+ fi
+
+ pagename="$1"
+
+ if [ -e "$pagename" ]; then
+ echo error: "$pagename" exists >&2
+ exit 1
+ fi
+
+ date=$(date)
+ echo '\[[!template id=draft]]' >> "$pagename"
+ echo "\[[!meta date=\"$date\"]]" >> "$pagename"
+ echo "\[[!tag draft]]" >> "$pagename"
+ git add "$pagename"
+ $EDITOR "$pagename"
+
+>>>>> -- [[Jon]]
--- /dev/null
+I'm getting a number of errors like this when running ikiwiki:
+
+ utf8 "\xA2" does not map to Unicode at /usr/local/share/perl/5.10.0/IkiWiki.pm line 739, <$in> chunk 1.
+
+I think it's because some of my files contain non-utf8, non-unicode, or somehow bad characters in them, probably fancy quotes and the like that have been copy-and-pasted from my web browser. The problem is that I have hundreds of files, I transferred them all over from pyblosxom to ikiwiki at once, and the error message doesn't tell me which file the error comes from. How can I fix this?
+
+Thanks
+-- seanh
+
+> Unfortunatly, these messages are logged by perl so there's no way to add
+> a filename to them.
+>
+> If you run the build in --verbose mode, you should see which page ikiwiki
+> is working on, and unless it inlines some other page, you can be pretty
+> sure that page contains invalid utf-8 if the message is then printed.
+>
+> Another option is to use the `isutf8` program from
+> [moreutils](http://kitenet.net/~joey/code/moreutils/),
+> and run it on each file, it will tell you the line number
+> and character position that is invalid. --[[Joey]]
--- /dev/null
+Dear users,
+
+
+using the directive inline, I want to show all pages (for example named 2008.10.2:foo.mdwn or 2009.12.3:bar.mdwn), whose date in the title are in the future. So in this example only the second one.
+
+I did not find a directive doing this in [[/ikiwiki/PageSpec]].
+
+Does somebody have an idea? I just came up with using a tag “recent” or using a separate folder. But this would be a quite some work to maintain this setup.
+
+
+Thanks,
+
+Paul
+
+> There's no such pagespec, and doing one is difficult, because such a
+> pagespec will change what it matches over time. So ikiwiki would have to
+> somehow figure out that pages matched by it yesterday no longer match,
+> and that pages containing the pagespec need to be rebuilt. Which means
+> you'd also need a cron job.
+
+>> Thank you for the explanation.
+
+> I suspect what you're trying to accomplish is
+> [[todo/tagging_with_a_publication_date]]? --[[Joey]]
+
+>> Yeah, something like that. Thanks! --[[PaulePanter]]
--- /dev/null
+Greetings.
+
+I am put this code in one page:
+[[!teximg code="\frac{1}{5}" alt="1/5"]]
+
+this is the configuration file ikiwiki.info:
+
+add_plugins => [qw{sidebar goodstuff textile html htmlscrubber table pagetemplate teximg map meta anonok img version textile txt}]
+
+ *Here the log*
+
+This is pdfTeXk, Version 3.141592-1.40.3 (Web2C 7.5.6) (format=latex 2008.8.4) 5 AUG 2008 10:01
+entering extended mode
+ %&-line parsing enabled.
+**/tmp/fb7742f8dd0c66473643ba40592e2be2.SBQfJo94ii/fb7742f8dd0c66473643ba40592e
+2be2.tex
+
+(/tmp/fb7742f8dd0c66473643ba40592e2be2.SBQfJo94ii/fb7742f8dd0c66473643ba40592e2
+be2.tex
+
+[...]
+
+Package scrkbase Info: You've used the obsolete option `12pt'.
+(scrkbase) \KOMAoptions{fontsize=12pt} will be used instead.
+(scrkbase) You should do this change too on input line 594.
+
+[...]
+
+! LaTeX Error: File `mhchem.sty' not found.
+
+Type X to quit or <RETURN> to proceed,
+or enter new name. (Default extension: sty)
+
+Enter file name:
+! Emergency stop.
+<read *>
+
+l.1 ...l}\usepackage[version=3]{mhchem}\usepackage
+
+ {amsmath}\usepackage{amsfo...
+
+(cannot \read from terminal in nonstop modes)
+
+
+Here is how much of TeX's memory you used:
+ 761 strings out of 94074
+ 10268 string characters out of 1167096
+ 66007 words of memory out of 1500000
+ 4120 multiletter control sequences out of 10000+50000
+ 3938 words of font info for 15 fonts, out of 1200000 for 2000
+ 645 hyphenation exceptions out of 8191
+ 30i,1n,28p,410b,45s stack positions out of 5000i,500n,6000p,200000b,10000s
+No pages of output.
+
+
+Some idea ?.
+
+>> It looks like teximg uses some less standard LaTeX packages. (see line 100 of Ikiwiki/Plugin/teximg.pm in the Ikiwiki source.)
+>> A quick work-around for an end-user would be to install the 'mhchem' LaTeX package (look in [CTAN](http://www.ctan.org/) ).
+>> A medium-term workaround would be to replace 'scrartcl' on line 100 with 'article', and delete line 101 in the teximg source.
+>> Longer term it would be nice to give teximg a configurable preamble.
+>> Hrm - maybe that configurable preamble should be a [[todo]]? -- [[users/Will]]
+
+>>>Yes it works. Thanks. I am writing some code for examples.
+
+
--- /dev/null
+Re [Let's just rely on backlinks for this?](http://git.ikiwiki.info/?p=ikiwiki;a=blobdiff;f=doc/ikiwiki/pagespec/discussion.mdwn;h=4eed3722ccc744595fc8380e68e69dc9e1ad6450;hp=f4fdd764ed61c34c09af9df046a1a134b7d0ffe6;hb=a4ce0468f6f562ad4ec749f156528aa5b3f2fe39;hpb=23a4ee6d15dbd9b8e8c6588a829dd30a26a8de32) and [2](http://git.ikiwiki.info/?p=ikiwiki;a=blobdiff;f=doc/ikiwiki/wikilink/discussion.mdwn;h=0677ff7ded6a86be7d010dfd97affdb6b266832a;hp=274c8aaf1d075adbf3b76496e1945348aefe836a;hb=4f4666c4ae5cdf5e04ac42cc52a97d90e978adb0;hpb=a4ce0468f6f562ad4ec749f156528aa5b3f2fe39):
+
+I simply didn't notice there is an "add a new bug" form at [[bugs]], so I used the obvious way to create a page through the web-interface: to put first a wikilink pointing at the new page. --Ivan Z.
--- /dev/null
+How do I setup an old ikiwiki repository on a new system?
+
+I have a git repository from an old ikiwiki system.
+I reformatted that hard drive, but saved the repository.
+
+I copied it the repository to my new system, which is now the "master" host.
+I installed ikiwiki on the new system.
+
+How do I set up an ikiwiki system using a pre-existing repository (instead of creating a new one)? --[[JosephTurian]]
+
+> Well, if you have:
+> * A git repository of the wiki
+> * A setup file for the wiki
+>
+> Then you should:
+>
+> 1. Manually set up a bare git repository, and push
+> your backed up repository to it.
+> 2. `git clone` from the bare git repository to
+> recreate the ikiwiki srcdir
+> 3. `git clone` from the bare git repository a second time,
+> to create a checkout you can manually edit (optional)
+> 4. run `ikiwiki --getctime --setup your.setup`
+> The getctime will ensure page creation times are accurate
+> by putting the info out of the git history,
+> and only needs to be done once.
+>
+> If you preserved your repository, but not the setup file,
+> the easiest way to make one is probably to run
+> `ikiwiki -dumpsetup` and edit the setup file. --[[Joey]]
+
+> > I get the following errors after running ikiwiki setup:
+
+ shortcut plugin will not work without shortcuts.mdwn
+ shortcut plugin will not work without shortcuts.mdwn
+ successfully generated /home/turian/public_html/iki/ikiwiki.cgi
+ shortcut plugin will not work without shortcuts.mdwn
+ successfully generated /home/turian/repos/iki.git/hooks/post-update
+ Can't stat /usr/share/ikiwiki/basewiki/../javascript: No such file or directory
+ at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Plugin/autoindex.pm line 60
+ Can't stat /usr/share/ikiwiki/basewiki/../smiley: No such file or directory
+ at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Plugin/autoindex.pm line 60
+ Can't stat /usr/share/ikiwiki/basewiki: No such file or directory
+ at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Plugin/autoindex.pm line 60
+ Can't stat /usr/share/ikiwiki/basewiki/../javascript: No such file or directory
+ at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Render.pm line 320
+ Can't stat /usr/share/ikiwiki/basewiki/../smiley: No such file or directory
+ at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Render.pm line 320
+ Can't stat /usr/share/ikiwiki/basewiki: No such file or directory
+ at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Render.pm line 320
+ internal error: smileys.mdwn cannot be found in /home/turian/iki or underlay
+
+> > How do I resolve these errors? I have my PERL5LIB location set correctly.
+
+>>> Well, that's unrelated to the original question, but
+>>> I guess you should set `underlaydir` in your setup file to
+>>> point to whereever you have installed the basewiki directory.
+>>> --[[Joey]]
--- /dev/null
+I'm trying to create a template to use as a sidebar with links. The template will be static
+(no variables are used). I first created a page with this directive: \[[!template id=sidebar]],
+and then created the template with the web interface.
+
+This is the code I put in the template:
+
+ <div class="infobox">
+ <ul>
+ <li>\[[Existing internal link|exists]]</li>
+ <li>\[[Non-existing internal link|doesnotexist]]</li>
+ <li>[External link](http://google.com/)</li>
+ </ul>
+ <http://google.com/>
+ </div>
+
+This is the relevant part of the resulting html file `template/sidebar.html`:
+
+ <div class="infobox">
+ <ul>
+ <li><a href="../exists.html">Existing internal link</a></li>
+ <li><span class="createlink"><a href="http://localhost/cgi-bin/itesohome.cgi?page=doesnotexist&from=templates%2Fsidebar&do=create" rel="nofollow">?</a>Non-existing internal link</span></li>
+ <li>[External link](http://google.com/)</li>
+ </ul>
+ </div>
+
+Note that the `<http://google.com/>` link has disappeared, and that `[External link](http://google.com/)`
+has been copied literally instead of being converted to a link, as I expected.
+
+> Templates aren't Markdown page. [[ikiwiki/WikiLink]] only are expanded. --[[Jogo]]
+
+>> Thanks for the help Jogo. Looking at the [[templates]] page, it says that
+"...you can include WikiLinks and all other forms of wiki markup in the template." I read this
+to mean that a template may indeed include Markdown. Am I wrong in my interpratation? --[[buo]]
+
+>> I discovered that if I eliminate all html from my sidebar.mdwn template, the links are
+rendered properly. It seems that the mix of Markdown and html is confusing some part of
+Ikiwiki. --[[buo]]
+
+Worse, this is the relevant part of the html file of the page that includes the template:
+
+ <div class="infobox">
+ <ul>
+ <li><span class="selflink">Existing internal link</span></li>
+ <li><span class="createlink"><a href="http://localhost/cgi-bin/itesohome.cgi?page=doesnotexist&from=research&do=create" rel="nofollow">?</a>Non-existing internal link</span></li>
+ <li>[External link](http://google.com/)</li>
+ </ul>
+ </div>
+
+Note that the `Existing internal link` is no longer a link. It is only text.
+
+What am I doing wrong? Any help or pointers will be appreciated. --[[buo]]
+
+-----
+
+I think I have figured this out. I thought the template was filled and then
+processed to convert Markdown to html. Instead, the text in each variable is
+processed and then the template is filled. I somehow misunderstood the
+[[templates]] page. -- [[buo]]
--- /dev/null
+Hi again,
+
+I have finally finished my setup *but* I still have a problem with RecentChanges page.
+
+Can somebody check it for me at [http://maillard.mobi/~xma/wiki/recentchanges/] and tell what is wrong ?
+
+Thank you.
+
+--[[xma]]
+
+> Looks to me like you don't have the meta plugin enabled. --[[Joey]]
+
+> > You are right. Now all is ok. --[[xma]]
--- /dev/null
+Hi,
+
+Can you give me a hint for showing if one user is logged or not. If user is logged, then I want to display the user name, as wikipedia or dokuwiki for example.
+Regards,
+Xan.
+
+> ikiwiki doesn't serve pages, so this can't be done inside ikiwiki.
+> For certain kinds of authentication it might be possible anyway.
+> For instance, if you're using [[plugins/httpauth]] exclusively and
+> your server has PHP, you could put `<?php print("$REMOTE_USER");
+> ?>` in all the relevant ikiwiki [[templates]] and arrange for the
+> generated HTML pages to get run through the PHP interpreter. The trick
+> would work differently with other [[plugins/type/auth]] plugins,
+> if at all. --[[Schmonz]]
+
+>> Thanks a lot, Xan.
+
+>>> Another possible trick would be to use some Javascript to make a
+>>> "who am I?" AJAX request to the CGI (the CGI would receive the
+>>> session cookie, if any, and be able to answer). Obviously, this
+>>> wouldn't work for users who've disabled Javascript, but since it's
+>>> non-essential, that's not so bad. You'd need to
+>>> [[write_a_plugin|plugins/write]] to add a suitable CGI action,
+>>> perhaps ?do=whoami, and insert the Javascript. --[[smcv]]
+
+>>>> It's an idea, but you're trading off a serious speed hit for a very
+>>>> minor thing. --[[Joey]]
+
+>>>> Cool idea. A similar trick (I first saw it
+>>>> [here](http://www.peej.co.uk/articles/http-auth-with-html-forms.html))
+>>>> could be used to provide a [[plugins/passwordauth]]-like login form
+>>>> for [[plugins/httpauth]]. --[[Schmonz]]
+
+>>>>> I always assumed the entire reason someone might want to use the
+>>>>> httpauth plugin is to avoid nasty site-specific login forms..
+>>>>> --[[Joey]]
--- /dev/null
+ [[!teximg code="\{}_pF_q(a_1,...,a_p;c_1,...,c_q;z) = \sum_{n=0}^\infty \frac{(a_1)_n\cdot\cdot\cdot(a_p)_n}{(c_1)_n\cdot\cdot\cdot(c_q)_n} \frac{z^n}{n!}"]]
+
+JAJAJA, the teximg is not loaded... :-(
+
+Bye.
+
+> This wiki does not have teximg enabled. --[[Joey]]
--- /dev/null
+just finished setting up ikiwiki..
+
+I can type chinese, save and display it correctly in ikiwiki for the first time. However, when i try to edit the page again, the chinese character in the form is unrecognizable. you can see it here <http://ikiwiki.perlchina.org/>
+
+I am using the latest ikiwiki(manually installed as non-root user) and CGI::FormBuilder(3.0501) on Debian 4.0
+
+这个没问题 it is not a problem on ikiwiki website though.
+
+Thanks.
+
+
+> Is your system perhaps not configured with a utf-8 default locale? Or ikiwiki not configured to use it?
+> Make sure that some utf-8 locale is enabled (in /etc/locale.gen on Debian for example) and try setting `locale` in your > ikiwiki setup file. --[[Joey]]
+
+I have installed locales-all and locale -a shows that zh_CN.UTF-8 is installed(there is no /etc/local.gen file though). then I enabled this line "locale => 'zh_CN.UTF-8'" in my wiki setup and -setup again. but that generated lots error messages "Missing constant domain at (eval 30) line 3"
+
+sorry being a n00b on this thing what else can I do?
+
+> See [[bugs/Missing_constant_domain_at_IkiWiki.pm_line_842]].
+> Looks like you need to upgrade to a newer version of
+> [[!cpan Locale::gettext]] --[[Joey]]
--- /dev/null
+I like the idea of this forum heirarchy -- but I think a map would be clearer than inlining the sub-pages. -- [[users/Jon]]
+
+> The easier way to accomplish this is to set archive=yes in the inline.
+> Switching to archive view can be useful when there are a lot of long
+> posts and people tend to want to scan by title to find interesting ones
+> and not necessarily read them all, which probably fits this forum pretty
+> well --[[Joey]]
--- /dev/null
+when I login via to this wiki (or ours) via Google's OpenID, I get this error:
+
+Error: OpenID failure: no_identity_server: The provided URL doesn't declare its OpenID identity server.
+
+Any idea how to fix this??
+
+> Google is [doing things with openid that are not in the spec](http://googledataapis.blogspot.com/2008/10/federated-login-for-google-account.html)
+> and it's not clear to me that they intend regular openid to work at all.
+> What is your google openid URL so I can take a look at the data they are
+> providing? --[[Joey]]
+
+
+http://openid-provider.appspot.com/larrylud
+
+> I've debugged this some and filed
+> <https://rt.cpan.org/Ticket/Display.html?id=48728> on the Openid perl
+> module. It's a pretty easy fix, so I hope upstream will fix it quickly.
+> --[[Joey]]
+
+>> A little more information here: I'm using that same openid provider at the moment. Note that
+>> that provider isn't google - it is someone using the google API to authenticate. I normally have it
+>> set up as a redirect from my home page (which means I can change providers easily).
+
+ <link rel="openid.server" href="http://openid-provider.appspot.com/will.uther">
+ <link rel="openid.delegate" href="http://openid-provider.appspot.com/will.uther">
+
+>> In that mode it works (I used it to log in to make this edit). However, when I try the openid
+>> URL directly, it doesn't work. I think there is something weird with re-direction. I hope this
+>> isn't a more general security hole.
+>> -- [[Will]]
--- /dev/null
+I'm having some difficulties with ikiwiki's notion of time.
+
+For (regular) pages, the *last edited* date is the one where the file
+was indeed last modified according to the file system information.
+The *created* date (commented out in the HTML) is, at least for
+`--getctime` operation, the date, where the file was last registered
+as changed with the VCS.
+
+Now, at least with git, the thing is that when you're checking out files,
+they'll get the checkout-time's current time stamp.
+
+What I strive for is the following: *created* be the date when the file
+(under its current name) was *first* registered with the VCS (which is
+more logical in my opinion), and *last edited* be the date the file was
+last registered as changed with the VCS, which is the current
+`--getctime` *created* date.
+
+This means that I can build the HTML files from different checkouts of the
+VCS and they won't differ in the time stamps they contain in the HTML.
+
+What is the rationale for ikiwiki's current behavior with respect to these
+time stamps?
+
+--[[tschwinge]]
+
+> Presumably it's the authors of the git and mercurial backends
+> not understanding the documentation for `rcs_getctime`,
+> which states:
+>
+>>This is used to get the page creation time for a file from the RCS, by
+>>looking it up in the history.
+>
+> I've fixed both broken implementations to correctly look
+> up the first, not the last, commit. Other VCS do not seem
+> to have the problem. --[[Joey]]
--- /dev/null
+Is there here any possibility to modifying ikiwiki (via plugin) for store pages in database. I'm thinking about storing pages in sqlite or mysql for serving it much faster. The idea is from sputnik.org [http://sputnik.freewisdom.org/] but with perl ;-). Could we integrate the sputnik code in ikiwiki as a solution?
+
+-----
+
+ikiwiki generates static pages in a filesystem. It's responsible for editing and regenerating them, but they're served by any old web server. If you go to the trouble of stuffing the generated pages into a database, you'll need to go to further trouble to serve them back out somehow: write your own web server, perhaps, or a module for a particular web server. Either way you'll have sacrificed ikiwiki's interoperability, and it's not at all clear (since you're adding, in the best case, one layer of indirection reading the generated files) you'll have gained any improved page-serving performance. If it's source pages you want to store in a database, then you lose the ability to do random Unixy things to source pages, including managing them in a revision control system.
+
+Static HTML pages in a filesystem and the ability to do random Unixy things are two of the uniquely awesome features of ikiwiki. It's probably possible to do what you want, but it's unlikely that you really want it. I'd suggest you either get to know ikiwiki better, or choose one of the many wiki implementations that already works as you describe. --[[Schmonz]]
+
+---
+
+Thanks, [[Schmonz]]. You clarify me much things,.... Xan.
--- /dev/null
+### "meta openid" problems
+
+I have add the followning to _index.mdwn_ on my site.
+
+ \[[!meta openid="http://certifi.ca/lunix"
+ server="http://certifi.ca/_serve"]]
+
+This resulted in the following being added to my site
+
+ <link href="http://certifi.ca/_serve" rel="openid.server" />
+ <link href="http://certifi.ca/_serve" rel="openid2.provider" />
+ <link href="http://certifi.ca/lunix" rel="openid.delegate" />
+ <link href="http://certifi.ca/lunix" rel="openid2.local_id" /> -->
+
+Perhaps I have done something wrong but this fails to work when I try to log in to several sites using my sites url as my login.
+If I edit index.html and remove the two openid2 lines all works fine.
+**Is there a way to only add openid version 1 tags to my index.html ?
+Or a way to make it work the way it is ?** --[Mick](http://www.lunix.com.au)
+
+> Before I think about adding a way to not add the openid 2 tags,
+> I'd like to know what the problem is. Is there something
+> wrong with the tags? Does your openid provider not support
+> openid 2, and the site you are logging into sees the openid 2 tags
+> and uses it, not falling back to openid 1?
+>
+> Since certifi.ca is a public openid provider (run by a
+> guy I know even!), I should be
+> able to reproduce your problem if you can tell me what
+> site(s) you are trying to log into. --[[Joey]]
+
+----------
+
+I was using _phpMyID_ and its not _openid2_ compliant so I switched to certifi.ca to counteract that but I really
+want to go back to running my own provider.
+I can't login to identi.ca.unless I comment out the openid2 lines.(this may be there problem, I get sent to certifi.ca's site and redirected back to identi.ca)
+I will test all the different openid enabled sites I log into today and see what happens.
+It seems that since I have moved my site to its final location and made it live over night I am able to login to most places now.
+I do not have a proper understanding of the inner workings of openid so not exactly sure what part is failing but I think the problem
+lays with the consumers not falling back to the openid1 tags when they are openid1 only consumers. --[Mick](http://www.lunix.com.au)
+
+> So, just to clarify, certifi.ca works ok (I verified this, logging into identi.ca using it).
+> You had the problem running your own openid provider which did not support 2.0, in which case,
+> consumers seem justified in not falling back (guess; I don't know the 2.0 spec).
+> The only way this seems fixable is to add an option to meta to allow disabling openid 2. Which
+> should be easy enough to do. --[[Joey]]
+
+I can't log into identi.ca with openid2 tags. strange. I will look at that again today.
+Having the option to disable openid2 tags would be perfect.
+Thanks Joey. --[Mick](http://www.lunix.com.au)
+
+>> Actually, it seems that identi.ca / certifi.ca do
+>> not interoperate when using openid2. It actually
+>> fails half the time, and succeeds half the time;
+>> seems to be picking openid1 and openid2 randomly and failing
+>> on the latter. I have emailed Evan Prodromou about this weird behavior.
+>> Not clear to me if identi.ca or certifi.ca is at fault,
+>> but luckily he runs both..
+>> --[[Joey]]
+
+Ahh so it's not just me.
+It's handy having contacts in the _right_ places. --[Mick](http://www.lunix.com.au)
+
+>> ikiwiki's next release will allow adding 'delegate=1' to the
+>> meta directive to only delegate to openid1. --[[Joey]]
+
+## awesome.
+--[Mick](http://www.lunix.com.au)
--- /dev/null
+I keep some TODO lists on ikiwiki pages. I'm half-tempted to write a plugin
+to make ticking items off and adding items easier via the web interface. I'm
+aware though that this is not really what ikiwiki is designed for. Would
+anyone else find this useful? -- [[users/jon]]
+
+----
+
+My subsequent thoughts about how to approach this are two-fold.
+
+Firstly, a filetype for todo lists, probably OPML, but I haven't looked to see
+if there is something more suitable. A plugin that converts this source into a
+traditional page output, i.e. a DOM tree of ul or ol and li elements.
+
+Secondly, some magic javascript to make editing the list via the web page
+more interactive: add items, strike items out, reorder items etc., without
+round-tripping to the cgi for each operation.
+
+Finally, a mechanism whereby the changes made to the page live can be
+committed back to the repository:
+
+ * ...perhaps the input → output conversion is reversible, and the HTML DOM
+ representing the list can be transformed back into the source and submitted
+ to the cgi like a regular edit: issues include the result of other
+ postprocessing: templates, wikilinks, etc.
+ * perhaps an embedded copy of the source is included in the output and the
+ javascript operates on that in tandem with the static copy
+ * perhaps the "output" is generated live by the JS at view time (with maybe
+ a plugin-generated rendered output for non JS environments)
+
+I envisage a button called "commit changes" appearing once some changes are
+made that submits the changes to the CGI, perhaps via a back channel. I'm not
+sure how to handle embeds or challenges from the CGI such as a login challenge
+(maybe the back channel would not be necessary in the first cut).
+
+> You might look at the [[plugins/hnb]] plugin. HNB supports checklists.
+> There's not a fancy web interface, but the hnb command-line program can
+> be used to edit them. --[[Joey]]
+
+>> thanks - I'll give it a look. I spent a few hours writing some javascript to manipulate a ul/li DOM tree in an outliner-fashion the other day. I might be able to join the puzzle pieces together sometime. [[Jon]]
+
+a solution for this could be similar to a solution for [[todo/structured page data]], as todo lists are definitely a form of structured data. (in both cases, the page's current content is rendered into a html form, whose result is then saved as the page's new contents) --[[chrysn]]
+
+> Thanks for the link: yup, there's definitely some common ground there.
+> -- [[Jon]]
--- /dev/null
+Dear developers and users,
+
+
+# Problem
+
+I am trying to set up ikiwiki for a website. Users should be able to edit pages using the webbrowser (ikiwiki.cgi) and a few should be able to edit it using versioning control and in this case Git.
+
+I have ikiwiki working for a single user (me), but I do not [[get_the_permissions_right|/rcs/Git]] for multiple users and commiters. The wiki admin does not own the Git repository in this case. And I do not understand everything yet (especially concerning wrappers).
+
+# Programs
+
+I am running Debian Etch with gitosis (0.2+20080626-2) installed from etch-backports, Apache2 (apache2.2-common 2.2.3-4+etch5) and ikiwiki (2.63) from Sid.
+
+# Goal
+
+* The website (run by ikiwiki) should be accessable via http://www.example.org/
+* Users can edit pages using the webbrowser.
+* Git is used as the backend.
+* The Git repository should be publicaly browsable via http://git.example.org/git/project.git (gitweb).
+* The Git repository can be accessed with git clone git://git.example.org/git/project.git (git-daemon).
+* Some manually set up users can push their changes over SSH to the repository and the post-update hook updates the wiki.
+
+# Directory Layout and permissions.
+
+## Website
+
+The website is stored in /srv/www/www.example.org/htdocs/ (destdir in ikiwiki.setup) and is owned by www-data:root with rights 755.
+
+## Git repository
+
+The [package gitosis](http://joey.kitenet.net/blog/entry/locking_down_ssh_authorized_keys/) creates an user gitosis with the home directory /srv/gitosis/ and the repository are stored in /srv/gitosis/repository/project.git owned by gitosis:gitosis and permissions 750. I can setup the permissions who is allowed to access this repository and if it should be published using git-daemon or gitweb in the configuration file gitosis.conf.
+
+# My efforts without results
+
+I could not come up with a working set of users which are put into different groups to create a good result with ikiwiki. The main problem is that under Debian umask is set to 022 which means that the members of a group are not allowed to write. I did not want to change this.
+
+> You can set the umask for ikiwiki itself, without changing the system umask, via the usmask setting in the setup file. --[[Joey]]
+
+In the end, I did the following. I created a directory /srv/ikiwiki/ which is owned by gitosis. The [[setup_file|/usage]] is also located there (/srv/ikiwiki/project.setup). I put the srcdir there too (srcdir => '/srv/ikiwiki/project/'). So now sudo -u gitosis ikiwiki --project.setup is able to create the post-update hook (git_wrapper => '/srv/gitosis/repositories/project.git/hooks/post-update'). Since this hook is called every time something is checked in over SSH, it is run by gitosis, so I did not set it suid. Or do I have to, because ikiwiki.cgi will be run as www-data?
+
+> Generally, ikiwiki.cgi is run as the user who owns the wiki and repository, in this case, gitosis. The ikwiiki.cgi needs to be able to write to source files in the wiki; it needs to be able to commit changes,
+> and it needs to be able to generate and write the html files. If you don't want ikiwiki.cgi to run as gitosis, you will need to put gitosis and www-data in a group and give them both write access, with appropriate umask, etc. --[[Joey]]
+
+## cgi_wrapper
+
+I do not understand those wrappers completely. The cgi is a script, which can be called by a webserver, e. g. [[Apache_2|/tips/dot_cgi]]. But www-data is normally not allowed to write to the source directory (which is owned by gitosis or push to the repository). Therefore it should be run as the user gitosis. And because cgi scripts can not be made suid, I wrapper (in this case a C program) is created (cgi\_wrapper) which can be made suid and therefore be run as the user gitosis. Is this correct?
+
+> It seems to me like you understand the wrapper pretty well. It's main reson to exist is to safely be suid, yes.
+
+So where is good place to save this wrapper? cgi_wrapper => '/srv/ikiwiki/project-wrapper'? Then /srv/ikiwiki/project-wrapper is created from a temporary C file prject-wrapper.c?
+
+
+No sudo -u gitosis ikikwiki --setup project.setup is still not able to put the compilation result into /srv/www/www.project.org/htdocs because this is owned by www-data. I just came up with two things.
+
+1. Set destdir => '/srv/ikiwiki/html-project', do ln -s /srv/ikiwiki/html-project /srv/www/www.example.org/htdocs and adduser www-data gitosis. But I am not sure about the security implications of using symbolic links.
+
+2. Since the webserver (Apache 2) has just to read the html files (is that true for static and dynamic (PHP) pages) sudo chown -R gitosis:www-data /srv/www/www.example.org/ should do it. But it is per default www-data:root under Debian, so I do not know if this should be changed.
+
+
+Could you please enlighten me. It should be possible seeing for example this site.
+
+> www-data is not really intended to own files. So that if the web server is compromised, it cannot rewrite your web site. So make the site's destdir be owned by the same user that ikiwiki runs as.
+> /srv/www is not shipped by debian; it is a bug in debian for any package to make files owned by www-data; so it seems to me that your /srv/www www-data ownership is something you must have configured yourself. --[[Joey]]
+
+Thanks in advance,
+
+--[[PaulePanter]]
--- /dev/null
+I don't know if I'm doing this right... I'm using a server provider that doesn't allow me to install into standard perl locations, so I used PREFIX to install things in my home dir. The problem is that when the wrapper is run by the CGI server, it can't find the perl modules I installed. There didn't seem to be a way to set the PERL5LIB from the standard config, so I added one. Patch attached. Or did I miss something and this was already possible?
+
+> The standard way to do it is to set `INSTALL_BASE=$HOME` when running
+> `Makefile.PL`. If you do this, ikiwiki will be built with a special `use
+> lib $HOME` line inserted, that will make it look in the specified
+> directory for perl modules.
+>
+> The [[tips/nearlyfreespeech]] tip has an example of doing this.
+> --[[Joey]]
+
+>> Thanks! I found that page, but didn't recognise the importance of INSTALL_BASE.
+
+>> It looks like INSTALL_BASE only appeared in version 6.31 of the Perl MakeMaker. My provider is still running version 6.30. Looks like I'll be keeping my patches for the moment... sigh.
--- /dev/null
+My website takes a fairly long time to render. It takes a long time to do
+things like add pages, too. I'd like to try and understand what takes the
+time and what I might be able to do to speed things up.
+
+I have 1,234 objects on my site (yikes!). 717 are items under "/log" which
+I think might be the main culprit because there are some complex pagespecs
+operating in that area (e.g. log/YYYY/MM/DD, YYYY/MM and YYYY for YYYY >=
+2003, YYYY <= 2008 which include every page under log/ which was modified
+in the corresponding YYYY or YYYY/MM or YYYY/MM/DD). There is very little
+linking between the world outside of /log and that within it.
+
+I was interested in generating a graphical representation of ikiwiki's idea of
+page inter-dependencies. I started by looking at the '%links' hash using the
+following plugin:
+
+ #!/usr/bin/perl
+ package IkiWiki::Plugin::deps;
+
+ use warnings;
+ use strict;
+ use IkiWiki 3.00;
+
+
+ sub import {
+ hook(type => "format", id => "deps", call => \&fooble);
+ }
+
+ my $hasrun = 0;
+
+ sub fooble ($$) {
+ if(0 == $hasrun) {
+ $hasrun = 1;
+ open MYFILE, ">/home/jon/deps.dot";
+ foreach my $key (keys %links) {
+ my $arrref = $links{$key};
+ foreach my $page (@$arrref) {
+ print MYFILE "$key -> $page;\n";
+ }
+ }
+ close MYFILE;
+ }
+ }
+
+ 1
+
+The resulting file was enormous: 2,734! This turns out to be because of the following code in scan() in Render.pm:
+
+ if ($config{discussion}) {$
+ # Discussion links are a special case since they're
+ # not in the text of the page, but on its template.
+ $links{$page}=[ $page."/".gettext("discussion") ];
+
+Worst case (no existing discussion pages) this will double the number of link
+relationships. Filtering out all of those, the output drops to 1,657. This
+number is still too large to really visualize: the graphviz PNG and PDF output
+engines segfault for me, the PS one works but I can't get any PS software to
+render it without exploding.
+
+Now, the relations in the links hash are not the same thing as IkiWiki's notion of dependencies. Can anyone point me at that data structure / where I might be able to add some debugging foo to generate a graph of it?
+
+Once I've figured out that I might be able to optimize some pagespecs. I
+understand pagespecs are essentially translated into sequential perl code. I
+might gain some speed if I structure my complex pagespecs so that the tests
+which have the best time complexity vs. "pages ruled out" ratio are performed
+first.
+
+I might also be able to find some dependencies which shouldn't be there and
+remove the dependency.
+
+In general any advice people could offer on profiling ikiwiki would be great.
+I did wonder about invoking the magic profiling arguments to perl via the CGI
+wrapper.
+
+
+-- [[Jon]]
+
+> Dependencies go in the `%IkiWiki::depends` hash, which is not exported. It
+> can also be dumped out as part of the wiki state - see [[tips/inside_dot_ikiwiki]].
+>
+> It's a map from page name to increasingly complex pagespec, although
+> the `optimize-depends` branch in my git repository changes that to a
+> map from a page name to a *list* of pagespecs which are automatically
+> or'd together for use (this at least means duplicates can be weeded out).
+>
+> See [[todo/should_optimise_pagespecs]] for more on that.
+>
+> I've been hoping to speed up IkiWiki too - making a lot of photo albums
+> with my [[plugins/contrib/album]] plugin makes it pretty slow.
+>
+> One thing that I found was a big improvement was to use `quick=yes` on all
+> my `archive=yes` [[ikiwiki/directive/inline]]s. --[[smcv]]
--- /dev/null
+Hi All;
+
+I'm trying to use a filter hook as part of making [[wikilinks|ikiwiki/wikilink]] work in [[plugins/contrib/tex4ht]].
+It seems that filter is called for every page. For my application I just want it to be called for ".tex" files,
+but right now I have to have a look at the content, which I don't like so much.
+
+Is there a better hook to use for this? I need to transform the input before preprocessing.
+
+[[DavidBremner]]
--- /dev/null
+My ikiwiki setup file configed like:
+
+ usedirs => 0,
+ indexpages => 1,
+
+I create a directory and some .mdwn source file /Whatis/index.mdwn and /Whatis/OSS.mdwn . The html file ikiwiki generated is
+/Whatis/index.html and /Whatis/OSS.html .
+
+But in the page [OSS.html](http://atoz.org.cn/Whatis/OSS.html) , the auto generated link (on the page top)
+to “Whatis” is /Whatis.html file , not to /Whatis/index.html. So the link to “Whatis” is fail .
+
+Is it a bug , and how can I do for that ?
+
+> I suggest that you name your page `Whatis.mdwn`, and not
+> `Whatis/index.mdwn`. That will make ikiwiki's links work,
+> and allows you to link to the `Whatis` page by that name.
+> --[[Joey]]
--- /dev/null
+I'd like to have the wiki name appear in page titles as in "WikiName:
+Page Title." If I use `<TMPL_VAR WIKINAME>: <TMPL_VAR TITLE>` in the
+template this works for all pages except the index page itself which
+will have title "WikiName: WikiName" as its title. Does anyone know
+of a template-based solution to this or do I need to write a plugin
+that provides a `IS_HOMEPAGE` template variable? --[[JasonBlevins]]
+
+> Hmm, one way to work around this is to put a meta title directive on the
+> index page. Then TITLE will be that, rather than WIKINAME, and your
+> template should work. --[[Joey]]
+
+>> I ended up writing a [path][] plugin since I had some other
+>> path-specific conditional things to include in my templates.
+>>
+>> So now I can do things like this:
+>>
+>> <title>
+>> <TMPL_VAR WIKINAME><TMPL_UNLESS IS_HOMEPAGE>: <TMPL_VAR TITLE></TMPL_UNLESS>
+>> </title>
+>>
+>> But also more complicated path-specific conditionals like
+>> `IN_DIR_SUBDIR` to indicate subpages of `/dir/subdir/`. I've got a
+>> few other small plugins brewing so I'll try to put up some contrib
+>> pages for them soon. --[[JasonBlevins]]
+
+[path]: http://code.jblevins.org/ikiwiki/plugins.git/plain/path.pm
-[[meta title="Free Software"]]
+[[!meta title="Free Software"]]
ikiwiki, and this documentation wiki, are licensed under the terms of the
GNU [[GPL]], version 2 or later.
--- /dev/null
+And where is the code, please ?
+
+> [[download]] --[[Joey]]
-Ikiwiki is developed in a git repository and can be checked out
-like this:
+Ikiwiki, and this documentation wiki, are developed in a git repository and
+can be checked out like this:
+
+[[!template id=note text="""
+You can push changes back to ikiwiki's git repository over the `git://`
+transport, to update this wiki, if you'd like, instead of editing it on the
+web. Changes that could not be made via the web will be automatically
+rejected.
+"""]]
git clone git://git.ikiwiki.info/
Commits to this git repository are fed into [CIA](http://cia.vc), and can
be browsed, subscribed to etc on its
-[project page](http://cia.vc/stats/project/ikiwiki).
+[project page](http://cia.vc/stats/project/ikiwiki). They're also fed into
+[twitter](http://twitter.com/ikiwiki).
-## branches
+## personal git repositories
You are of course free to set up your own ikiwiki git repository with your
-own [[patches|patch]].
+own [[patches|patch]]. If you list it here, the `gitremotes` script will
+automatically add it to git remotes. Your repo will automatically be pulled
+into [[Joey]]'s working tree. This is recommended. :-)
+
+<!-- Machine-parsed format: * wikilink <git:url> -->
+
+* github `git://github.com/joeyh/ikiwiki.git`
+ ([browse](http://github.com/joeyh/ikiwiki/tree/master))
+ A mirror of the main repo, automatically updated.
+* l10n `git://l10n.ikiwiki.info/`
+ Open push localization branch used for <http://l10n.ikiwiki.info/>
+* [[smcv]] `git://git.pseudorandom.co.uk/git/smcv/ikiwiki.git`
+* [[intrigeri]] `git://gaffer.ptitcanardnoir.org/ikiwiki.git`
+* [[gmcmanus]] `git://github.com/gmcmanus/ikiwiki.git`
+* [[jelmer]] `git://git.samba.org/jelmer/ikiwiki.git`
+* [[hendry]] `git://webconverger.org/git/ikiwiki`
+* [[jon]] `git://github.com/jmtd/ikiwiki.git`
+* [[ikipostal|DavidBremner]] `git://pivot.cs.unb.ca/git/ikipostal.git`
+* [[ikimailbox|DavidBremner]] `git://pivot.cs.unb.ca/git/ikimailbox.git`
+* [[ikiplugins|DavidBremner]] `git://pivot.cs.unb.ca/git/ikiplugins.git`
+* [[jonas|JonasSmedegaard]] `git://source.jones.dk/ikiwiki-upstream`
+* [[arpitjain]] `git://github.com/arpitjain11/ikiwiki.git`
+* [[chrysn]] `git://github.com/github076986099/ikiwiki.git`
+* [[simonraven]] `git://github.com/kjikaqawej/ikiwiki-simon.git`
+* [[schmonz]] `git://github.com/schmonz/ikiwiki.git`
+
+## branches
Some of the branches included in the main repository include:
instead of xhtml.
* `wikiwyg` adds [[todo/wikiwyg]] support. It is unmerged pending some
changes.
+* `debian-stable` is used for updates to the old version included in
+ Debian's stable release, and `debian-testing` is used for updates to
+ Debian's testing release.
* `pristine-tar` contains deltas that
[pristine-tar](http://kitenet.net/~joey/code/pristine-tar)
can use to recreate released tarballs of ikiwiki
-* `debian-stable` is used for updates to the old version included in
- Debian's stable release.
# SYNOPSIS
-ikiwiki-makerepo svn|git srcdir repository
+ikiwiki-makerepo svn|git|monotone|darcs srcdir repository
-ikiwiki-makerepo mercurial srcdir
+ikiwiki-makerepo bzr|mercurial srcdir
# DESCRIPTION
`ikiwiki-makerepo` injects a `srcdir` directory, containing an ikiwiki wiki,
-into a `repository` that it creates. The repository can be a svn, git, or
-mercurial repository.
+into a `repository` that it creates. The repository can be created using
+any of a variety of revision control systems.
-Note that for mercurial, the srcdir is converted into a mercurial
-repository. There is no need to have a separate repository with mercurial.
+Note that for mercurial and bzr, the srcdir is converted into a
+repository. There is no need to have a separate repository with mercurial
+or bzr.
+
+For darcs, the master repo's apply hook will be preconfigured to call a
+ikiwiki wrapper.
+
+Note that for monotone, you are assumed to already have run "mtn genkey"
+to generate a key.
# AUTHOR
# DESCRIPTION
-`ikiwiki-transition` aids in converting wiki pages when
-there's a major change in ikiwiki syntax. It also handles other transitions
-not involving wiki pages.
+`ikiwiki-transition` aids in converting wiki pages when there's a major
+change in ikiwiki syntax. It also handles other transitions not involving
+wiki pages.
-# prefix_directives
+# prefix_directives your.setup
-The `prefix_directives` mode converts the specified ikiwiki page from
-the old preprocessor directive syntax, requiring a space, to the new
-syntax, prefixed by '!'.
+The `prefix_directives` mode converts all pages from the old preprocessor
+directive syntax, requiring a space, to the new syntax, prefixed by '!'.
Preprocessor directives which already use the new syntax will remain
unchanged.
-Note that if the page contains wiki links with spaces, which some
+Note that if a 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.
-# indexdb
+# setupformat your.setup
+
+The `setupformat` mode converts a setup file from using a single `wrappers` block
+to using `cgi_wrapper`, `git_wrapper`, etc.
+
+Note that all comments and any unusual stuff like perl code in the setup
+file will be lost, as it is entirely rewritten by the transition.
+
+# aggregateinternal your.setup
+
+The `aggregateinternal` mode moves pages aggregated by the aggregate plugin
+so that the `aggregateinternal` option can be enabled.
+
+# moveprefs your.setup
+
+Moves values that used to be admin preferences into the setup file.
+
+Note that all comments and any unusual stuff like perl code in the setup
+file will be lost, as it is entirely rewritten by the move.
+
+# indexdb your.setup|srcdir
The `indexdb` mode handles converting a plain text `.ikiwiki/index` file to
-a binary `.ikiwiki/indexdb`. In this mode, you should specify the srcdir of
-the wiki as the second parameter. You do not normally need to run
+a binary `.ikiwiki/indexdb`. You do not normally need to run
`ikiwiki-transition indexdb`; ikiwiki will automatically run it as
necessary.
-# hashpassword
+# hashpassword your.setup|srcdir
The `hashpassword` mode forces any plaintext passwords stored in the
`.ikiwiki/userdb` file to be replaced with password hashes. (The
-Authen::Passphrase perl module is needed to do this.) In this mode, you
-should specify the srcdir of the wiki as the second parameter.
+Authen::Passphrase perl module is needed to do this.)
If this is not done explicitly, a user's plaintext password will be
automatically converted to a hash when a user logs in for the first time
after upgrade to ikiwiki 2.48.
+# deduplinks your.setup
+
+In the past, bugs in ikiwiki have allowed duplicate link information
+to be stored in its indexdb. This mode removes such duplicate information,
+which may speed up wikis afflicted by it. Note that rebuilding the wiki
+will have the same effect.
+
# AUTHOR
Josh Triplett <josh@freedesktop.org>, Joey Hess <joey@ikiwiki.info>
# SYNOPSIS
-ikiwiki-update-wikilist
+ikiwiki-update-wikilist [-r]
# DESCRIPTION
-`ikiwiki-update-wikilist` is designed to be made suid root, but not installed
+`ikiwiki-update-wikilist` is designed to be made suid root, but is not installed
suid by default. If made suid, it allows users to add or remove their names
-from the `/etc/ikiwiki/wikilist` file. If a user's name is not in the file,
-it will be added; if the name is already present, it will be removed.
+from the `/etc/ikiwiki/wikilist` file.
+
+By default, the user's name will be added.
+The `-r` switch causes the user's name to be removed.
If your name is in `/etc/ikiwiki/wikilist`, the [[ikiwiki-mass-rebuild]](8)
command will look for a ~/.ikiwiki/wikilist file, and rebuild the wikis listed
Some documentation on using ikiwiki:
* [[ikiwiki/formatting]]
-* [[ikiwiki/blog]]
-* [[ikiwiki/pagespec]]
-* [[ikiwiki/PreprocessorDirective]]
* [[ikiwiki/wikilink]]
-* [[ikiwiki/markdown]]
* [[ikiwiki/subpage]]
+* [[ikiwiki/pagespec]]
+* [[ikiwiki/directive]]
+* [[ikiwiki/markdown]]
* [[ikiwiki/openid]]
* [[ikiwiki/searching]]
+++ /dev/null
-#!/usr/bin/perl
-# Configuration file for ikiwiki.
-# Passing this to ikiwiki --setup will make ikiwiki generate wrappers and
-# build the wiki.
-#
-# Remember to re-run ikiwiki --setup any time you edit this file.
-
-use IkiWiki::Setup::Standard {
- wikiname => "MyWiki",
- #adminuser => ["yourname", ],
- adminemail => 'me@example.org',
-
- # Be sure to customise these..
- srcdir => "/path/to/source",
- destdir => "/var/www/wiki",
-
- url => "http://example.org/wiki",
- cgiurl => "http://example.org/wiki/ikiwiki.cgi",
- #templatedir => "/usr/share/ikiwiki/templates",
- #underlaydir => "/usr/share/ikiwiki/basewiki",
-
- # Subversion stuff.
- #rcs => "svn",
- #historyurl => "http://svn.example.org/trunk/[[file]]",
- #diffurl => "http://svn.example.org/trunk/[[file]]?root=wiki&r1=[[r1]]&r2=[[r2]]",
- #svnrepo => "/svn/wiki",
- #svnpath => "trunk",
-
- # Git stuff.
- #rcs => "git",
- #historyurl => "http://git.example.org/gitweb.cgi?p=wiki.git;a=history;f=[[file]]",
- #diffurl => "http://git.example.org/gitweb.cgi?p=wiki.git;a=blobdiff;h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_parent]];f=[[file]]",
- #gitorigin_branch => "origin",
- #gitmaster_branch => "master",
-
- # Tla stuff.
- #rcs => "tla"
- #historyurl => ??,
- #diffurl => ??,
-
- # Mercurial stuff.
- #rcs => "mercurial",
- #historyurl => "http://localhost:8000/log/tip/[[file]]", # hg serve'd local repository
- #diffurl => "http://localhost:8000/?fd=[[r2]];file=[[file]]",
-
- # Bazaar stuff.
- #rcs => "bzr",
- #historyurl => "",
- #diffurl => "http://example.com/revision?start_revid=[[r2]]#[[file]]-s", # using loggerhead
-
- # Monotone stuff
- #rcs => "monotone",
- #mtnkey => "web\@machine.company.com",
- #historyurl => "http://viewmtn.example.com/branch/head/filechanges/com.example.branch/[[file]]",
- #diffurl => "http://viewmtn.example.com/revision/diff/[[r1]]/with/[[r2]]/[[file]]",
- # Set if you want the wiki to sync on update and commit.
- #mtnsync => 0,
- # The path to your workspace (defaults to the srcdir itself)
- # e.g. use if your srcdir is a subdirectory of the workspace.
- #mtnrootdir => "path/to/root/of/workspace",
-
- wrappers => [
- #{
- # # The cgi wrapper.
- # cgi => 1,
- # wrapper => "/var/www/wiki/ikiwiki.cgi",
- # wrappermode => "06755",
- #},
- #{
- # # The svn post-commit wrapper.
- # # Note that this will overwrite any existing
- # # post-commit hook script, which may not be
- # # what you want.
- # wrapper => "/svn/wikirepo/hooks/post-commit",
- # wrappermode => "04755",
- # # Log to syslog since svn post-commit hooks
- # # hide output and errors.
- # syslog => 1,
- #},
- #{
- # # The git post-update wrapper.
- # # Note that this will overwrite any existing
- # # post-update hook script, which may not be
- # # what you want.
- # wrapper => "/git/wiki.git/hooks/post-update",
- # wrappermode => "06755",
- #},
- #{
- # # The monotone netsync hook.
- # wrapper => "path/to/root/of/workspace/_MTN/ikiwiki-netsync-hook",
- # wrappermode => "06755",
- #},
- ],
-
- # Default to generating rss feeds for pages with feeds?
- #rss => 1,
- # Default to generating atom feeds for pages with feeds?
- #atom => 1,
- # Allow generating feeds even if not generated by default?
- #allowrss => 1,
- #allowatom => 1,
- # Urls to ping with XML-RPC when feeds are updated
- #pingurl => [qw{http://rpc.technorati.com/rpc/ping}],
- # Include discussion links on all pages?
- discussion => 1,
- # To exclude files matching a regexp from processing. This adds to
- # the default exclude list.
- #exclude => qr/\.wav$/,
- # To change the extension used for generated html files.
- #htmlext => 'htm',
- # Time format (for strftime)
- #timeformat => '%c',
- # Locale to use. Must be a UTF-8 locale.
- #locale => 'en_US.UTF-8',
- # Only send cookies over SSL connections.
- #sslcookie => 1,
- # Logging settings:
- #verbose => 1,
- syslog => 0,
- # To link to user pages in a subdirectory of the wiki.
- #userdir => "users",
- # To create output files named page.html rather than page/index.html.
- #usedirs => 0,
- # Simple spam prevention: require an account-creation password.
- #account_creation_password => "example",
- # Cost of generating a password using Authen::Passphrase::BlowfishCrypt
- #password_cost => 8,
- # Uncomment to force ikiwiki to run with a particular umask.
- #umask => 022,
- # Default settings for the recentchanges page.
- #recentchangespage => "recentchanges",
- #recentchangesnum => 100,
- # Use new '!'-prefixed preprocessor directive syntax
- #prefix_directives => 0,
- # Attempt to make hardlinks to source files instead of copying them.
- # Useful if the wiki contains large media files.
- #hardlink => 1,
- # Enable use of multimarkdown features in .mdwn files.
- #multimarkdown => 1,
-
- # To add plugins, list them here.
- #add_plugins => [qw{goodstuff search wikitext camelcase
- # htmltidy fortune sidebar map rst anonok}],
- # If you want to disable any of the default plugins, list them here.
- #disable_plugins => [qw{inline htmlscrubber passwordauth openid}],
- # To add a directory to the perl search path, use this.
- #libdir => "/home/me/.ikiwiki/",
-
- # To override environment variable settings, you can list values here.
- #ENV => {
- # TZ => "America/New_York",
- # PATH => "/home/me/bin:/usr/local/bin:/usr/bin:/bin",
- #},
-
- # For use with the tag plugin, make all tags be located under a
- # base page.
- #tagbase => "tag",
-
- # For use with the search plugin if the omega cgi is located
- # somewhere else.
- #omega_cgi => "/usr/lib/cgi-bin/omega/omega",
-
- # For use with the openid plugin, to give an url to a page users
- # can use to signup for an OpenID.
- #openidsignup => "http://myopenid.com/",
-
- # For use with the mirrorlist plugin, a list of mirrors.
- #mirrorlist => {
- # mirror1 => "http://hostname1",
- # mirror2 => "http://hostname2/mirror",
- #},
-
- # For use with the anonok plugin, a PageSpec specifying what
- # pages anonymous users can edit
- #anonok_pagespec => "*",
-
- # For use with the aggregate plugin, to allow aggregation to be
- # triggered via the web.
- #aggregate_webtrigger => 1,
-
- # For use with the pinger plugin, how many seconds to wait before
- # timing out.
- #pinger_timeout => 15.
-
- # For use with the amazon S3 plugin, your public access key id.
- #amazon_s3_key_id => 'XXXXXXXXXXXXXXXXXXXX',
- # And a file holding your secret key. This file *must* not be
- # readable by others!
- #amazon_s3_key_file => "/home/me/.hide/.s3_key
- # The globally unique name of the bucket to use to store the wiki.
- #amazon_s3_bucket => "mywiki",
- # A prefix to prepend to each page name.
- #amazon_s3_prefix => "wiki/",
- # Uncomment to use the S3 European datacenter.
- #amazon_s3_location => "EU",
- # Uncomment if you need to store each index file twice.
- #amazon_s3_dupindex => 1,
-
- # For use with the attachment plugin, a program that returns
- # nonzero if its standard input contains an virus.
- #virus_checker => "clamdscan -",
-}
+++ /dev/null
-[[!meta robots="noindex, follow"]]
-[[!if test="enabled(inline)"
- then="This wiki has the inline plugin **enabled**."
- else="This wiki has the inline plugin **disabled**."]]
-
-[[!if test="enabled(inline)"
- then="You can"
- else="If this wiki had the inline plugin enabled, you could"]]
-turn any page on this wiki into a weblog by using the `inline`
-[[PreProcessorDirective]]. For example:
-
- \[[!inline pages="blog/* and !*/Discussion" show="10" rootpage="blog"]]
-
-Any pages that match the specified [[PageSpec]] (in the example, any
-[[SubPage]] of "blog") will be part of the blog, and the newest 10
-of them will appear in the page. Note that if files that are not pages
-match the [[PageSpec]], they will be included in the feed using RSS
-enclosures, which is useful for podcasting.
-
-The optional `rootpage` parameter tells the wiki that new posts to this blog
-should default to being [[SubPage]]s of "blog", and enables a form at the
-top of the blog that can be used to add new items.
-
-If you want your blog to have an archive page listing every post ever made
-to it, you can accomplish that like this:
-
- \[[!inline pages="blog/* and !*/Discussion" archive="yes"]]
-
-You can even create an automatically generated list of all the pages on the
-wiki, with the most recently added at the top, like this:
-
- \[[!inline pages="* and !*/Discussion" archive="yes"]]
-
-If you want to be able to add pages to a given blog feed by tagging them,
-you can do that too. To tag a page, just make it link to a page or pages
-that represent its tags. Then use the special `link()` [[PageSpec]] to match
-all pages that have a given tag:
-
- \[[!inline pages="link(life)"]]
-
-Or include some tags and exclude others:
-
- \[[!inline pages="link(debian) and !link(social)"]]
-
-## usage
-
-Here are descriptions of all the supported parameters to the `inline`
-directive:
-
-* `pages` - A [[PageSpec]] of the pages to inline.
-* `show` - Specify the maximum number of matching pages to inline.
- Default is 10, unless archiving, when the default is to show all.
- Set to 0 to show all matching pages.
-* `skip` - Specify a number of pages to skip displaying. Can be useful
- to produce a feed that only shows archived pages.
-* `rss` - controls generation of an rss feed. If the wiki is configured to
- generate rss feeds by default, set to "no" to disable. If the wiki is
- configured to `allowrss`, set to "yes" to enable.
-* `atom` - controls generation of an atom feed. If the wiki is configured to
- generate atom feeds by default, set to "no" to disable. If the wiki is
- configured to `allowatom`, set to "yes" to enable.
-* `feeds` - controls generation of all types of feeds. Set to "no" to
- disable generating any feeds.
-* `postform` - Set to "yes" to enables a form to post new pages to a [[blog]].
-* `postformtext` - Set to specify text that is displayed in a postform.
-* `rootpage` - Also enables a form to post new pages to a [[blog]], and
- allows specifying of a page that is used as the parent page for new pages.
-* `archive` - If set to "yes", only list page titles and some metadata, not
- full controls.
-* `quick` - Build archives in quick mode, without reading page contents for
- metadata. By default, this also turns off generation of any feeds.
-* `template` - Specifies the template to fill out to display each inlined
- page. By default the `inlinepage` template is used, while
- the `archivepage` template is used for archives. Set this parameter to
- use some other, custom template, such as the `titlepage` template that
- only shows post titles. Note that you should still set `archive=yes` if
- your custom template does not include the page content.
-* `raw` - Rather than the default behavior of creating a [[blog]],
- if raw is set to "yes", the page will be included raw, without additional
- markup around it, as if it were a literal part of the source of the
- inlining page.
-* `description` - Sets the description of the rss feed if one is generated.
- Defaults to the name of the wiki.
-* `actions` - If set to "yes" add links to the bottom of the inlined pages
- for editing and discussion (if they would be shown at the top of the page
- itself).
-* `sort` - Controls how inlined pages are sorted. The default, "age" is to
- sort newest created pages first. Setting it to "title" will sort pages by
- title, and "mtime" sorts most recently modified pages first.
-* `reverse` - If set to "yes", causes the sort order to be reversed.
-* `feedpages` - A [[PageSpec]] of inlined pages to include in the rss/atom
- feeds. The default is the same as the `pages` value above, and only pages
- matches by that value are included, but some of those can be excluded by
- specifying a tighter [[PageSpec]] here.
-* `feedshow` - Specify the maximum number of matching pages to include in
- the rss/atom feeds. The default is the same as the `show` value above.
-* `feedonly` - Only generate the feed, do not display the pages inline on
- the page.
-* `timeformat` - Use this to specify how to display the time or date for pages
- in the blog. The format string is passed to the strftime(3) function.
+++ /dev/null
-## How do you provide the per post discussion links in your own blog?
-
-> That's configured by the "actions" parameter to the inline directive. See
-> docs in [[plugins/inline]]. --[[Joey]]
-
-And do you have any ideas/hints about implementing a "comments" feature.
-What I'm after is something for users who don't quite understand the Wiki
-style for discussions. I would like to have a form for them to post a
-comment and have the comment appended to the discussion Wiki-style. Maybe
-take it as far as implementing "replies" to other comments.
-
--- Marcelo
-
-> See [[todo/discussion_page_as_blog]] for some of my own thoughts on this
-> --[[Joey]]
-
----
-
-## More dynamic `rootpage` parameter of inline plugin?
-
-(Moved to [[todo/dynamic_rootpage]])
--- /dev/null
+[[!meta robots="noindex, follow"]]
+Directives are similar to a [[ikiwiki/WikiLink]] in form, except they
+begin with `!` and may contain parameters. The general form is:
+
+ \[[!directive param="value" param="value"]]
+
+This gets expanded before the rest of the page is processed, and can be used
+to transform the page in various ways.
+
+The quotes around values can be omitted if the value is a simple word.
+Also, some directives may use parameters without values, for example:
+
+ \[[!tag foo]]
+
+A directive does not need to all be on one line, it can be
+wrapped to multiple lines if you like:
+
+ \[[!directive foo="baldersnatch"
+ bar="supercalifragilisticexpialidocious" baz=11]]
+
+Also, multiple lines of *quoted* text can be used for a value.
+To allow quote marks inside the quoted text, delimit the block
+of text with triple-quotes:
+
+ \[[!directive text="""
+ 1. "foo"
+ 2. "bar"
+ 3. "baz"
+ """]]
+
+ikiwiki also has an older syntax for directives, which requires a space in
+directives to distinguish them from [[wikilinks|ikiwiki/wikilink]]. This
+syntax has several disadvantages: it requires a space after directives with
+no parameters (such as `\[[pagecount ]]`), and it prohibits spaces in
+[[wikilinks|ikiwiki/wikilink]]. ikiwiki now provides the `!`-prefixed
+syntax shown above as default. However, ikiwiki still supports wikis using
+the older syntax, if the `prefix_directives` option is disabled.
+
+[[!if test="enabled(listdirectives)" then="""
+Here is a list of currently available directives in this wiki:
+
+[[!listdirectives ]]
+"""]]
--- /dev/null
+The `aggregate` directive is supplied by the [[!iki plugins/aggregate desc=aggregate]] plugin.
+This plugin requires extra setup, specifically, a cron job. See the
+plugin's documentation for details.
+
+This directive allows content from other feeds to be aggregated into the wiki.
+Aggregate a feed as follows:
+
+ \[[!aggregate name="example blog" dir="example"
+ feedurl="http://example.com/index.rss"
+ url="http://example.com/" updateinterval="15"]]
+
+That example aggregates posts from the specified RSS feed, updating no
+more frequently than once every 15 minutes (though possibly less
+frequently, if the cron job runs less frequently than that), and puts a
+page per post under the example/ directory in the wiki.
+
+You can then use ikiwiki's [[inline]] directive to create a blog of one or
+more aggregated feeds. For example:
+
+ \[[!inline pages="internal(example/*)"]]
+
+Note the use of `internal()` in the [[ikiwiki/PageSpec]] to match
+aggregated pages. By default, aggregated pages are internal pages,
+which prevents them from showing up directly in the wiki, and so this
+special [[PageSpec]] is needed to match them.
+
+## usage
+
+Here are descriptions of all the supported parameters to the `aggregate`
+directive:
+
+* `name` - A name for the feed. Each feed must have a unique name.
+ Required.
+* `url` - The url to the web page for the feed that's being aggregated.
+ Required.
+* `dir` - The directory in the wiki where pages should be saved. Optional,
+ if not specified, the directory is based on the name of the feed.
+* `feedurl` - The url to the feed. Optional, if it's not specified ikiwiki
+ will look for feeds on the `url`. RSS and atom feeds are supported.
+* `updateinterval` - How often to check for new posts, in minutes. Default
+ is 15 minutes.
+* `expireage` - Expire old items from this feed if they are older than
+ a specified number of days. Default is to never expire on age.
+* `expirecount` - Expire old items from this feed if there are more than
+ the specified number total. Oldest items will be expired first. Default
+ is to never expire on count.
+* `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 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.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `brokenlinks` directive is supplied by the [[!iki plugins/brokenlinks desc=brokenlinks]] plugin.
+
+This directive generates a list of broken links on pages in the wiki. This is
+a useful way to find pages that still need to be written, or links that
+are written wrong.
+
+The optional parameter "pages" can be a [[ikiwiki/PageSpec]] specifying the
+pages to search for broken links, default is search them all.
+
+Example:
+
+ \[[!brokenlinks pages="* and !recentchanges"]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+Would it be possible to have such a thing also checking for external links? -- [[user/emptty]]
--- /dev/null
+The `calendar` directive is supplied by the [[!iki plugins/calendar desc=calendar]] plugin.
+This plugin requires extra setup. See the plugin documentation for details.
+
+This directive displays a calendar, similar to the typical calendars shown on
+some blogs.
+
+# examples
+
+ \[[!calendar ]]
+
+ \[[!calendar type="month" pages="blog/* and !*/Discussion"]]
+
+ \[[!calendar type="year" year="2005" pages="blog/* and !*/Discussion"]]
+
+The calendar is essentially a fancy front end to archives of previous
+pages, usually used for blogs. It can produce a calendar for a given month,
+or a list of months for a given year.
+
+The month format calendar simply links to any page posted on each
+day of the month. The year format calendar links to archive pages, with
+names like `archives/2007` (for all of 2007) and `archives/2007/01`
+(for January, 2007). For this to work, you'll need to create these archive
+pages. They typically use [[inline]] to display or list pages created in
+the given time frame.
+
+## usage
+
+* `type` - Used to specify the type of calendar wanted. Can be one of
+ "month" or "year". The default is a month view calendar.
+* `pages` - Specifies the [[ikiwiki/PageSpec]] of pages to link to from the
+ month calendar. Defaults to "*".
+* `archivebase` - Configures the base of the archives hierarchy. The
+ default is "archives". Note that this default can also be overridden
+ for the whole wiki by setting `archivebase` in ikiwiki's setup file.
+* `year` - The year for which the calendar is requested. Defaults to the
+ current year.
+* `month` - The numeric month for which the calendar is requested, in the
+ range 1..12. Used only for the month view calendar, and defaults to the
+ current month.
+* `week_start_day` - A number, in the range 0..6, which represents the day
+ of the week that the month calendar starts with. 0 is Sunday, 1 is Monday,
+ and so on. Defaults to 0, which is Sunday.
+* `months_per_row` - In the annual calendar, number of months to place in
+ each row. Defaults to 3.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `color` directive is supplied by the [[!iki plugins/color desc=color]] plugin.
+
+This directive can be used to color a piece of text on a page.
+It can be used to set the foreground and/or background color of the text.
+
+You can use a color name (e.g. `white`) or HTML code (e.g. `#ffffff`)
+to define colors.
+
+## examples
+
+Here the foreground color is defined as a word, while the background color
+is defined as a HTML color code:
+
+ \[[!color foreground=white background=#ff0000 text="White text on red background"]]
+
+The background color is missing, so the text is displayed on default
+background:
+
+ \[[!color foreground=white text="White text on default color background"]]
+
+The foreground is missing, so the text has the default foreground color:
+
+ \[[!color background=#ff0000 text="Default color text on red background"]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `comment` directive is supplied by the
+[[!iki plugins/comments desc=comments]] plugin, and is used to add a comment
+to a page. Typically, the directive is the only thing on a comment page,
+and is filled out by the comment plugin when a user posts a comment.
+
+Example:
+
+ \[[!comment format=mdwn
+ username="foo"
+ subject="Bar"
+ date="2009-06-02T19:05:01Z"
+ content="""
+ Blah blah.
+ """
+ ]]
+
+## usage
+
+The only required parameter is `content`, the others just add or override
+metadata of the comment.
+
+* `content` - Text to display for the comment.
+ Note that [[directives|ikiwiki/directive]]
+ may not be allowed, depending on the configuration
+ of the comment plugin.
+* `format` - Specifies the markup used for the content.
+* `subject` - Subject for the comment.
+* `date` - Date the comment was posted. Can be entered in
+ nearly any format, since it's parsed by [[!cpan TimeDate]]
+* `username` - Used to record the username (or OpenID)
+ of a logged in commenter.
+* `ip` - Can be used to record the IP address of a commenter,
+ if they posted anonymously.
+* `claimedauthor` - Records the name that the user entered,
+ if anonmous commenters are allowed to enter their (unverified)
+ name.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+[[!meta redir=/ikiwiki/directive/cutpaste]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+[[!meta redir=/ikiwiki/directive/cutpaste]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `copy`, `cut` and `paste` directives are supplied by the
+[[!iki plugins/cutpaste desc=cutpaste]] plugin.
+
+With these directives you can store and recall pieces of text in a page:
+
+ * `\[[!cut id=name text="text"]]` memorizes the text allowing to recall it
+ using the given ID. The text being cut is not included in the output.
+ * `\[[!copy id=name text="text"]]` memorizes the text allowing to recall it
+ using the given ID. The text being cut *is* included in the output.
+ * `\[[!paste id=name]]` is replaced by the previously memorized text.
+
+The text being cut, copied and pasted can freely include wiki markup, including
+more calls to cut, copy and paste.
+
+You do not need to memorize the text before using it: a cut directive can
+follow the paste directive that uses its text. In fact, this is quite useful
+to postpone big blocks of text like long annotations and have a more natural
+flow. For example:
+
+ \[[!toggleable id="cut" text="[[!paste id=cutlongdesc]]"]]
+ \[[!toggleable id="copy" text="[[!paste id=copylongdesc]]"]]
+ \[[!toggleable id="paste" text="[[!paste id=pastelongdesc]]"]]
+
+ [...some time later...]
+
+ \[[!cut id=cutlongdesc text="""
+ blah blah blah
+ """]]
+ \[[!cut id=copylongdesc text="""
+ blah blah blah
+ """]]
+ \[[!cut id=pastelongdesc text="""
+ blah blah blah
+ """]]
+
+This can potentially be used to create loops, but ikiwiki is clever and breaks
+them.
+
+Since you can paste without using double quotes, copy and paste can be used to
+nest directives that require multiline parameters inside each other:
+
+ \[[!toggleable id=foo text="""
+ [[!toggleable id=bar text="[[!paste id=baz]]"]]
+ """]]
+
+ \[[!cut id=baz text="""
+ multiline parameter!
+ """]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `edittemplate` directive is supplied by the [[!iki plugins/edittemplate desc=edittemplate]] plugin.
+
+This directive allows registering template pages, that provide default
+content for new pages created using the web frontend. To register a
+template, insert a [[ikiwiki/directive/template]] directive on some other page.
+
+ \[[!edittemplate template="bugtemplate" match="bugs/*"]]
+
+In the above example, the page named "bugtemplate" is registered as a
+template to be used when any page named "bugs/*" is created. To avoid
+the directive displaying a note about the template being registered, add
+"silent=yes".
+
+Often the template page contains a simple skeleton for a particular type of
+page. For the bug report pages in the above example, it might look
+something like:
+
+ Package:
+ Version:
+ Reproducible: y/n
+ Details:
+
+The template page can also contain [[!cpan HTML::Template]] directives,
+similar to other ikiwiki [[templates]]. Currently only one variable is
+set: `<TMPL_VAR name>` is replaced with the name of the page being
+created.
+
+----
+
+It's generally not a good idea to put the `edittemplate` directive in
+the template page itself, since the directive would then be included as
+part of the template on new pages, which would then in turn be registered
+as templates. If multiple pages are registered as templates for a new page,
+an arbitrary one is chosen, so that could get confusing.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `format` directive is supplied by the [[!iki plugins/format desc=format]]
+plugin.
+
+The directive allows formatting a chunk of text using any available page
+format. It takes two parameters. First is the type of format to use,
+ie the extension that would be used for a standalone file of this type.
+Second is the text to format.
+
+For example, this will embed an otl outline inside a page using mdwn or
+some other format:
+
+ \[[!format otl """
+ foo
+ 1
+ 2
+ bar
+ 3
+ 4
+ """]]
+
+Note that if the highlight plugin is enabled, this directive can also be
+used to display syntax highlighted code. Many languages and formats are
+supported. For example:
+
+ \[[format perl """
+ print "hello, world\n";
+ """]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `fortune` directive is supplied by the [[!iki plugins/fortune desc=fortune]] plugin.
+
+This just uses the `fortune` program to insert a fortune cookie into the page.
+Usage:
+
+ \[[!fortune ]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `graph` directive is supplied by the [[!iki plugins/graphviz desc=graphviz]] plugin.
+
+This directive allows embedding [graphviz](http://www.graphviz.org/) graphs in a
+page. Example usage:
+
+ \[[!graph src="a -> b -> c; a -> c;"]]
+
+Note that graphs will only show up in previews if your browser has
+[[!wikipedia data: URI]] support, or if the same graph already exists on that
+page.
+
+The `graph` directive supports the following parameters:
+
+- `src` - The graphviz source to render.
+- `type` - The type of graph to render: `graph` or `digraph`. Defaults to
+ `digraph`.
+- `prog` - The graphviz program to render with: `dot`, `neato`, `fdp`, `twopi`,
+ or `circo`. Defaults to `dot`.
+- `height`, `width` - Limit the size of the graph to a given height and width,
+ in inches. You must specify both to limit the size; otherwise, graphviz will
+ choose a size, without any limit.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `haiku` directive is supplied by the [[!iki plugins/haiku desc=haiku]] plugin.
+
+This directive allows inserting a randomly generated haiku into a wiki page.
+Just type:
+
+ \[[!haiku hint="argument"]]
+
+[[!haiku hint="argument test"]]
+
+The hint parameter can be omitted, it only provides the generator a hint of
+what to write the haiku about. If no hint is given, it might base it on the
+page name. Since the vocabulary it knows is very small, many hints won't
+affect the result at all.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `if` directive is supplied by the [[!iki plugins/conditional desc=conditional]] plugin.
+
+With this directive, you can make text be conditionally displayed on a page.
+For example:
+
+ \[[!if test="enabled(smiley)"
+ then="The smiley plugin is enabled :-)"
+ else="No smiley plugin here.."]]
+
+If the specified `test` succeeds, the `then` text will be displayed,
+otherwise the `else` text will be displayed. The `else` part is optional.
+
+The `then` and `else` values can include any markup that would be allowed
+in the wiki page outside the template. Triple-quoting the values even allows
+quotes to be included.
+
+The `test` is a [[ikiwiki/PageSpec]]; if it matches any page in the wiki
+then it succeeds. So you can do things like testing for the existence of a
+page or pages, testing to see if any pages were created in a given month,
+and so on.
+
+If you want the [[ikiwiki/PageSpec]] to only match against the page that
+contains the conditional, rather than matching against all pages in the
+wiki, set the "all" parameter to "no".
+
+In an `if` directive, the regular [[ikiwiki/PageSpec]] syntax is expanded
+with the following additional tests:
+
+* enabled(plugin)
+
+ Tests whether the specified plugin is enabled.
+
+* sourcepage(glob)
+
+ Tests whether the glob matches the name of the page that contains the
+ conditional.
+
+* destpage(glob)
+
+ Tests whether the glob matches the name of the page that is being built.
+ That might be different than the name of the page that contains the
+ conditional, if it's being inlined into another page.
+
+* included()
+
+ Tests whether the page is being included onto another page.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `img` directive is supplied by the [[!iki plugins/img desc=img]] plugin.
+
+This is an image handling directive. While ikiwiki supports inlining full-size
+images by making a [[ikiwiki/WikiLink]] that points to the image, using
+this directive you can easily scale down an image for inclusion onto a page,
+providing a link to a full-size version.
+
+## usage
+
+ \[[!img image1.jpg size="200x200" alt="clouds"]]
+
+The image file will be searched for using the same rules as used to find
+the file pointed to by a [[ikiwiki/WikiLink]].
+
+The `size` parameter is optional, defaulting to full size. Note that the
+original image's aspect ratio is always preserved, even if this means
+making the image smaller than the specified size. You can also specify only
+the width or the height, and the other value will be calculated based on
+it: "200x", "x200"
+
+You can also pass `alt`, `title`, `class`, `align` and `id` parameters.
+These are passed through unchanged to the html img tag. If you include a
+`caption` parameter, the caption will be displayed centered beneath the image.
+
+The `link` parameter is used to control whether the scaled down image links
+to the full size version. By default it does; set "link=somepage" to link
+to another page instead, or "link=no" to disable the link, or
+"link=http://url" to link to a given url.
+
+You can also set default values that will be applied to all later images on
+the page, unless overridden. Useful when including many images on a page.
+
+ \[[!img defaults size=200x200 alt="wedding photo"]]
+ \[[!img photo1.jpg]]
+ \[[!img photo2.jpg]]
+ \[[!img photo3.jpg size=200x600]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `inline` directive is supplied by the [[!iki plugins/inline desc=inline]] plugin.
+
+This is a directive that allows including one wiki page inside another.
+The most common use of inlining is generating blogs and RSS or Atom feeds.
+
+Example:
+
+ \[[!inline pages="blog/* and !*/Discussion" show="10" rootpage="blog"]]
+
+Any pages that match the specified [[PageSpec]] (in the example, any
+[[SubPage]] of "blog") will be part of the blog, and the newest 10
+of them will appear in the page. Note that if files that are not pages
+match the [[PageSpec]], they will be included in the feed using RSS
+enclosures, which is useful for podcasting.
+
+The optional `rootpage` parameter tells the wiki that new posts to this
+blog should default to being [[SubPages|SubPage]] of "blog", and enables a
+form at the top of the blog that can be used to add new items.
+
+If you want your blog to have an archive page listing every post ever made
+to it, you can accomplish that like this:
+
+ \[[!inline pages="blog/* and !*/Discussion" archive="yes"]]
+
+You can even create an automatically generated list of all the pages on the
+wiki, with the most recently added at the top, like this:
+
+ \[[!inline pages="* and !*/Discussion" archive="yes"]]
+
+If you want to be able to add pages to a given blog feed by tagging them,
+you can do that too. To tag a page, just make it link to a page or pages
+that represent its tags. Then use the special `link()` [[PageSpec]] to match
+all pages that have a given tag:
+
+ \[[!inline pages="link(life)"]]
+
+Or include some tags and exclude others:
+
+ \[[!inline pages="link(debian) and !link(social)"]]
+
+## usage
+
+There are many parameters you can use with the `inline`
+directive. These are the commonly used ones:
+
+* `pages` - A [[PageSpec]] of the pages to inline.
+* `show` - Specify the maximum number of matching pages to inline.
+ Default is 10, unless archiving, when the default is to show all.
+ Set to 0 to show all matching pages.
+* `archive` - If set to "yes", only list page titles and some metadata, not
+ full contents.
+* `description` - Sets the description of the rss feed if one is generated.
+ Defaults to the name of the wiki.
+* `skip` - Specify a number of pages to skip displaying. Can be useful
+ to produce a feed that only shows archived pages.
+* `postform` - Set to "yes" to enable a form to post new pages to a
+ blog.
+* `postformtext` - Set to specify text that is displayed in a postform.
+* `rootpage` - Enables the postform, and allows controling where
+ newly posted pages should go, by specifiying the page that
+ they should be a [[SubPage]] of.
+
+Here are some less often needed parameters:
+
+* `actions` - If set to "yes" add links to the bottom of the inlined pages
+ for editing and discussion (if they would be shown at the top of the page
+ itself).
+* `rss` - controls generation of an rss feed. If the wiki is configured to
+ generate rss feeds by default, set to "no" to disable. If the wiki is
+ configured to `allowrss`, set to "yes" to enable.
+* `atom` - controls generation of an atom feed. If the wiki is configured to
+ generate atom feeds by default, set to "no" to disable. If the wiki is
+ configured to `allowatom`, set to "yes" to enable.
+* `feeds` - controls generation of all types of feeds. Set to "no" to
+ disable generating any feeds.
+* `emptyfeeds` - Set to "no" to disable generation of empty feeds.
+ Has no effect if `rootpage` or `postform` is set.
+* `template` - Specifies the template to fill out to display each inlined
+ page. By default the `inlinepage` template is used, while
+ the `archivepage` template is used for archives. Set this parameter to
+ use some other, custom template, such as the `titlepage` template that
+ only shows post titles or the `microblog` template, optimised for
+ microblogging. Note that you should still set `archive=yes` if
+ your custom template does not include the page content.
+* `raw` - Rather than the default behavior of creating a blog,
+ if raw is set to "yes", the page will be included raw, without additional
+ markup around it, as if it were a literal part of the source of the
+ inlining page.
+* `sort` - Controls how inlined pages are sorted. The default, "age" is to
+ sort newest created pages first. Setting it to "title" will sort pages by
+ title, and "mtime" sorts most recently modified pages first. If
+ [[!cpan Sort::Naturally]] is installed, `sort` can be set to "title_natural"
+ to sort by title with numbers treated as such ("1 2 9 10 20" instead of
+ "1 10 2 20 9").
+* `reverse` - If set to "yes", causes the sort order to be reversed.
+* `feedshow` - Specify the maximum number of matching pages to include in
+ the rss/atom feeds. The default is the same as the `show` value above.
+* `feedonly` - Only generate the feed, do not display the pages inline on
+ the page.
+* `quick` - Build archives in quick mode, without reading page contents for
+ metadata. By default, this also turns off generation of any feeds.
+* `timeformat` - Use this to specify how to display the time or date for pages
+ in the blog. The format string is passed to the strftime(3) function.
+* `feedpages` - A [[PageSpec]] of inlined pages to include in the rss/atom
+ feeds. The default is the same as the `pages` value above, and only pages
+ matched by that value are included, but some of those can be excluded by
+ specifying a tighter [[PageSpec]] here.
+* `guid` - If a URI is given here (perhaps a UUID prefixed with `urn:uuid:`),
+ the Atom feed will have this as its `<id>`. The default is to use the URL
+ of the page containing the `inline` directive.
+* `feedfile` - Can be used to change the name of the file generated for the
+ feed. This is particularly useful if a page contains multiple feeds.
+ For example, set "feedfile=feed" to cause it to generate `page/feed.atom`
+ and/or `page/feed.rss`. This option is not supported if the wiki is
+ configured not to use `usedirs`.
+* `pagenames` - If given instead of `pages`, this is interpreted as a
+ space-separated list of links to pages (with the same
+ [[SubPage/LinkingRules]] as in a [[ikiwiki/WikiLink]]), and they are inlined
+ in exactly the order given: the `sort` and `pages` parameters cannot be used
+ in conjunction with this one.
+
+[[!meta robots="noindex, follow"]]
+
+A related directive is the [[ikiwiki/directive/edittemplate]] directive, which allows
+default text for a new page to be specified.
--- /dev/null
+## How do you provide the per post discussion links in your own blog?
+
+> That's configured by the "actions" parameter to the inline directive. See
+> docs in [[plugins/inline]]. --[[Joey]]
+
+And do you have any ideas/hints about implementing a "comments" feature.
+What I'm after is something for users who don't quite understand the Wiki
+style for discussions. I would like to have a form for them to post a
+comment and have the comment appended to the discussion Wiki-style. Maybe
+take it as far as implementing "replies" to other comments.
+
+-- Marcelo
+
+> See [[plugins/comments]]
+> --[[Joey]]
+
+---
+
+## More dynamic `rootpage` parameter of inline plugin?
+
+(Moved to [[todo/dynamic_rootpage]])
+
+---
+
+## Excluding Images
+
+Is there a simple way to exclude images, stylesheets, and other
+"non-page" files other than a blacklist approach like
+`pages="* and !*.png and !*.css"`? --[[JasonBlevins]]
+
+> The [[plugins/filecheck]] plugin adds a 'ispage()' pagespec test that can do that.
+> --[[Joey]]
+
+---
+
+## Documentation for parameter `template`?
+
+I would be especially interested in a list of variables which can be used in such a template.
+
+> I try to keep ikiwiki's templates self-documenting, so if you take
+> a look at a template used by inline, such as the default `/usr/share/ikiwiki/template/inlinepage.tmpl`,
+> you can see all or nearly all the template variables in use in it.
+
+I have a page template with some structured information as parameters. For
+example `location="nowhere"` and `price="20"`. Is there a possibility to
+extract those information, i. e. access the parameters, to compose the item
+for the inline directive from these information? For example the line »Go
+to nowhere for 20 bugs.« is shown inlined.
+
+--[[PaulePanter]]
+
+> Let's not confuse the template directive with the templates used by inline.
+> When a page is inlined, any template directives in it are first expanded,
+> using the user-defined templates for that. Then, the inline directive's
+> template is used to insert it into the inlining page.
+>
+> So no, you can't reference template directive parameters inside inline's
+> template, because it's already expanded at that point. --[[Joey]]
+
+>> Thank you for the explanation. Can you think of another way to accomplish
+>> my goals?
+>>
+>> Right now, I only see the option to edit the title with the
+>> `[[/ikiwiki/directive/meta]]` directive and the field `title`.
+>>
+>> How could a solution look like?
+>>
+>> 1. The possibility to add custom fields to the `meta` directive.
+>> 1. The possibility to specify in a page, how the page should be displayed
+>> when used by inlined. That could be done by a new directive `cinlined`
+>> (for »custom inlined«) which is chosen by the `inline` directive to
+>> display if told to do so.
+>>
+>> [[!cinlined text="""Text which can also use Parameter, bla blubb …"""]]
+>> --[[PaulePanter]]
+>>> You can make the body of a page change depending on whether it's being
+>>> inlined, with the [[ikiwiki/directive/if]] directive from the
+>>> [[plugins/conditional]] plugin:
+>>>
+>>> \[[!if test="inlined()"
+>>> then="""[[!template id=productsummary
+>>> location="Warehouse 23" price=20
+>>> ]]"""
+>>> else="""[[!template id=productdetail
+>>> location="Warehouse 23" price=20
+>>> description="Every home should have one"
+>>> ]]"""
+>>> ]]
+>>>
+>>> Perhaps that does some of what you want?
+>>>
+>>> If you want to go beyond that, my inclination would be to write
+>>> a simple plugin to deal with whatever it is you want to do (bug
+>>> metadata or product metadata or whatever) rather than prematurely
+>>> generalizing. --[[smcv]]
+
+## meta parameters are not enough
+
+I think I have the same problem as Paule, as I want extra arbitary parameters in my template.
+
+This is what I am doing currently, which makes my skin crawl. In `wgts/foo.mdwn`
+I have resorted to using AUTHORURL as the location of this widgets icon:
+
+ [[!meta authorurl="/ico/aHR0cDovL2JvbmRpLm9tdHAub3JnL3dpZGdldHMvYmF0dGVyeQ==.png" ]]
+
+In templates I have a file called `wgtlist.tmpl`:
+
+ <div class="widget">
+ <TMPL_IF NAME="AUTHORURL">
+ <img src="<TMPL_VAR AUTHORURL>" />
+ </TMPL_IF>
+ <TMPL_IF NAME="PERMALINK">
+ <a href="<TMPL_VAR PERMALINK>"><TMPL_VAR TITLE></a><br />
+ <TMPL_ELSE>
+ <a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a><br />
+ </TMPL_IF>
+ Posted <TMPL_VAR CTIME>
+ </div>
+
+My index page has:
+
+ [[!inline pages="./wgts/*" show=5 feeds=no actions=no rootpage="wgts" archive="yes" template=wgtlist]]
+
+Else can you please suggest a smarter way of getting certain data out from pages for a inline index?
+
+--[[hendry]]
--- /dev/null
+The `linkmap` directive is supplied by the [[!iki plugins/linkmap desc=linkmap]] plugin.
+
+This directive uses [graphviz](http://www.graphviz.org/) to generate a
+graph showing the links between a set of pages in the wiki. Example usage:
+
+ \[[!linkmap pages="* and !blog/* and !*/Discussion"]]
+
+Only links between mapped pages will be shown; links pointing to or from
+unmapped pages will be omitted. If the pages to include are not specified,
+the links between all pages (and other files) in the wiki are mapped. For
+best results, only a small set of pages should be mapped, since otherwise
+the map can become very large, unwieldy, and complicated. Also, the map is
+rebuilt whenever one of the mapped pages is changed, which can make the
+wiki a bit slow.
+
+Here are descriptions of all the supported parameters to the `linkmap`
+directive:
+
+* `pages` - A [[ikiwiki/PageSpec]] of the pages to map.
+* `height`, `width` - Limit the size of the map to a given height and width,
+ in inches. Both must be specified for the limiting to take effect, otherwise
+ the map's size is not limited.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `listdirectives` directive is supplied by the [[!iki plugins/listdirectives desc=listdirectives]] plugin.
+
+This directive generates a list of available
+[[directives|ikiwiki/directive]].
+
+ \[[!listdirectives]]
+
+There is one optional keyword argument, `generated`. Normally the
+`listdirectives` directive will list all built in directives and directives
+directly registered by plugins. With this keyword, `listdirectives` will
+also list directives generated later. For example, all [[shortcuts]] are
+directives generated in turn by the `shortcut` directive. They will only
+be listed if the `generated` argument is supplied.
+
+ \[[!listdirectives generated]]
+
+This extended list is often quite long, and often contains many
+undocumented directives.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `map` directive is supplied by the [[!iki plugins/map desc=map]] plugin.
+
+This directive generates a hierarchical page map for the wiki. Example usage:
+
+ \[[!map pages="* and !blog/* and !*/Discussion"]]
+
+If the pages to include are not specified, all pages (and other files) in
+the wiki are mapped.
+
+By default, the names of pages are shown in the map. The `show` parameter
+can be used to show the titles or descriptions of pages instead (as set by
+the [[meta]] directive). For example:
+
+ \[[!map pages="* and !blog/* and !*/Discussion" show=title]]
+
+Hint: To limit the map to displaying pages less than a certain level deep,
+use a [[ikiwiki/PageSpec]] like this: `pages="* and !*/*/*"`
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+Question: Is there a way to generate a listing that shows *both* title and description meta information? Currently, a \[\[!map ...]] shows only one of the two, but I'd like to generate a navigation that looks like a description list. For example:
+
+ * This is the title meta information.
+
+ This is the description meta information
+
+ * This is another title.
+
+ And so on ...
+
+Is that possible?
+
+--Peter
+
+----
+
+The site I'm trying to set up right now (not really a wiki - no public editing) is divided into topics. Topics are pages that have `\[[!meta link="/topic"]]`. Topic pages contain an index of their subpages (done with `\[[!inline]]`); the subpages are the real content. I want a map in the sidebar that lists:
+
+ * all of the topics;
+ * all of the first-level subpages of the *current topic only*.
+
+That is, if the current page is "Topic A" or "Topic A/Page 1", then the map should look like
+
+ Topic A
+ Page 1
+ Page 2
+ Page 3
+ Topic B
+ Topic C
+
+but if the current page is "Topic B" or one of its subpages, then the map should look like
+
+ Topic A
+ Topic B
+ Page 1
+ Page 2
+ Page 3
+ Topic C
+
+On the top-level index page, or on any other page that is neither a topic nor a subpage of a topic, the map should list only the topics.
+
+Is there any way to do that? I don't mind mucking around with `\[[!meta]]` on every page if that's what it takes.
+
+-- Zack
+
+> I think that you're looking for this:
+>
+> `pages="((Topic*/* or Topic*) and ./*) or (Topic* and ! Topic*/*)"`
+>
+> Let's pull that [[PageSpec]] apart.
+>
+> * `(Topic*/* or Topic*)` matches all pages that are underneath a Topic
+> page or are a topic page themselves.
+> * `and ./*` further adds the limitation that the pages have to be
+> in the same directory as the page that is displaying the map. So,
+> for `Topic_A/Page_1`, it will match `Topic_A/*`; for `Topic_A`,
+> it will match `Topic_*` but not subpages.
+> * Finally, `Topic* and ! Topic*/*` matches all the toplevel topic pages,
+> since we always want those to show up.
+>
+> I haven't tested that this works or displays, but I hope it gets you
+> on the right track. PS, be aware of
+> [[this_sidebar_issue|todo/Post-compilation_inclusion_of_the_sidebar]]!
+> --[[Joey]]
+
+>> Thanks, but this assumes that topic pages are named `Topic<something>`.
+>> They aren't. They are tagged with `\[[!meta link="/topic"]]`, and as
+>> far as I can tell there is no [[PageSpec]] notation for "subpages of a
+>> page that satisfies link(foo)"...
+>> -- Zack
+
+>>> I think that the ideas and code in
+>>> [[todo/tracking_bugs_with_dependencies]] might also handle this case.
+>>> --[[Joey]]
--- /dev/null
+The `meta` directive is supplied by the [[!iki plugins/meta desc=meta]] plugin.
+
+This directive allows inserting arbitrary metadata into the source of a page.
+Enter the metadata as follows:
+
+ \[[!meta field="value"]]
+ \[[!meta field="value" param="value" param="value"]]
+
+The first form sets a given field to a given value, while the second form
+also specifies some additional sub-parameters.
+
+The field values are treated as HTML entity-escaped text, so you can include
+a quote in the text by writing `"` and so on.
+
+Supported fields:
+
+* title
+
+ Overrides the title of the page, which is generally the same as the
+ page name.
+
+ Note that if the title is overridden, a "title_overridden" variable will
+ be set to a true value in the template; this can be used to format things
+ differently in this case.
+
+* license
+
+ Specifies a license for the page, for example, "GPL". Can contain
+ WikiLinks and arbitrary markup.
+
+* copyright
+
+ Specifies the copyright of the page, for example, "Copyright 2007 by
+ Joey Hess". Can contain WikiLinks and arbitrary markup.
+
+* author
+
+ Specifies the author of a page.
+
+* authorurl
+
+ Specifies an url for the author of a page.
+
+* description
+
+ Specifies a "description" of the page. You could use this to provide
+ a summary, for example, to be picked up by the [[map]] directive.
+
+* permalink
+
+ Specifies a permanent link to the page, if different than the page
+ generated by ikiwiki.
+
+* date
+
+ Specifies the creation date of the page. The date can be entered in
+ nearly any format, since it's parsed by [[!cpan TimeDate]].
+
+* stylesheet
+
+ Adds a stylesheet to a page. The stylesheet is treated as a wiki link to
+ a `.css` file in the wiki, so it cannot be used to add links to external
+ stylesheets. Example:
+
+ \[[!meta stylesheet=somestyle rel="alternate stylesheet"
+ title="somestyle"]]
+
+* openid
+
+ Adds html <link> tags to perform OpenID delegation to an external
+ OpenID server. This lets you use an ikiwiki page as your OpenID.
+
+ By default this will delegate for both `openid` and `openid2`. To only
+ delegate for one, add a parameter such as `delegate=openid`.
+
+ An optional `xrds-location`
+ parameter lets you specify the location of any [eXtensible Resource
+ DescriptorS](http://www.windley.com/archives/2007/05/using_xrds.shtml).
+
+ Example:
+
+ \\[[!meta openid="http://joeyh.myopenid.com/"
+ server="http://www.myopenid.com/server"
+ xrds-location="http://www.myopenid.com/xrds?username=joeyh.myopenid.com""]]
+
+* link
+
+ Specifies a link to another page. This can be used as a way to make the
+ wiki treat one page as linking to another without displaying a user-visible
+ [[ikiwiki/WikiLink]]:
+
+ \[[!meta link=otherpage]]
+
+ It can also be used to insert a html <link> tag. For example:
+
+ \[[!meta link="http://joeyh.myopenid.com/" rel="openid.delegate"]]
+
+ However, this latter syntax won't be allowed if the
+ [[!iki plugins/htmlscrubber desc=htmlscrubber]] plugin is enabled, since it can be used to
+ insert unsafe content.
+
+* redir
+
+ Causes the page to redirect to another page in the wiki.
+
+ \[[!meta redir=otherpage]]
+
+ Optionally, a delay (in seconds) can be specified. The default is to
+ redirect without delay.
+
+ It can also be used to redirect to an external url. For example:
+
+ \[[!meta redir="http://example.com/"]]
+
+ However, this latter syntax won't be allowed if the
+ [[!iki plugins/htmlscrubber desc=htmlscrubber]] plugin is enabled, since it can be used to
+ insert unsafe content.
+
+ For both cases, an anchor to jump to inside the destination page may also be
+ specified using the common `#ANCHOR` syntax.
+
+* robots
+
+ Causes the robots meta tag to be written:
+
+ \[[!meta robots="index, nofollow"]]
+
+ Valid values for the attribute are: "index", "noindex", "follow", and
+ "nofollow". Multiple comma-separated values are allowed, but obviously only
+ some combinations make sense. If there is no robots meta tag, "index,
+ follow" is used as the default.
+
+ The value is escaped, but its contents are not otherwise checked.
+
+* guid
+
+ Specifies a globally unique ID for a page. This guid should be a URI
+ (in particular, it can be `urn:uuid:` followed by a UUID, as per
+ [[!rfc 4122]]), and it will be used to identify the page's entry in RSS
+ and Atom feeds. If not given, the default is to use the page's URL as its
+ guid.
+
+ This is mostly useful when a page has moved, to keep the guids for
+ pages unchanged and avoid_flooding_aggregators
+ (see [[!iki tips/howto_avoid_flooding_aggregators]]).
+
+* updated
+
+ Specifies a fake modification time for a page, to be output into RSS and
+ Atom feeds. This is useful to avoid flooding aggregators that sort by
+ modification time, like Planet: for instance, when editing an old blog post
+ to add tags, you could set `updated` to be one second later than the original
+ value. The date/time can be given in any format that
+ [[!cpan TimeDate]] can understand, just like the `date` field.
+
+If the field is not one of the above predefined fields, the metadata will be
+written to the generated html page as a <meta> header. However, this
+won't be allowed if the [[!iki plugins/htmlscrubber desc=htmlscrubber]] plugin is enabled,
+since it can be used to insert unsafe content.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `more` directive is supplied by the [[!iki plugins/more desc=more]] plugin.
+
+This directive provides a way to have a "more" link on a post in a blog, that
+leads to the full version of the page. Use it like this:
+
+ \[[!more linktext="click for more" text="""
+ This is the rest of my post. Not intended for people catching up on
+ their blogs at 30,000 feet. Because I like to make things
+ difficult.
+ """]]
+
+If the `linktext` parameter is omitted it defaults to just "more".
+
+Note that you can accomplish something similar using a [[toggle]] instead.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `orphans` directive is supplied by the [[!iki plugins/orphans desc=orphans]] plugin.
+
+This directive generates a list of possibly orphaned pages -- pages that no
+other page links to. Example:
+
+ \[[!orphans pages="* and !blog/*"]]
+
+The optional parameter "pages" can be a [[ikiwiki/PageSpec]] specifying the
+pages to check for orphans, default is search them all.
+
+Note that it takes backlinks into account, but does not count inlining a
+page as linking to it, so will generally count many blog-type pages as
+orphans.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `pagecount` directive is supplied by the [[!iki plugins/pagecount desc=pagecount]] plugin.
+
+This directive counts pages currently in the wiki. Example:
+
+ \[[!pagecount pages="*"]]
+
+The optional parameter "pages" can be a [[ikiwiki/PageSpec]] specifying the
+pages to count, default is to count them all.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `pagestats` directive is supplied by the [[!iki plugins/pagestats desc=pagestats]] plugin.
+
+This directive can generate stats about how pages link to each other. It can
+produce either a tag cloud, or a table counting the number of links to each
+page.
+
+Here's how to use it to create a [[tag]] cloud:
+
+ \[[!pagestats pages="tags/*"]]
+
+And here's how to create a table of all the pages on the wiki:
+
+ \[[!pagestats style="table"]]
+
+The optional `among` parameter limits counting to pages that match a
+[[ikiwiki/PageSpec]]. For instance, to display a cloud of tags used on blog
+entries, you could use:
+
+ \[[!pagestats pages="tags/*" among="blog/posts/*"]]
+
+or to display a cloud of tags related to Linux, you could use:
+
+ \[[!pagestats pages="tags/* and not tags/linux" among="tagged(linux)"]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+I am trying to create a tag cloud using:
+
+ \[[!pagestats pages="tags/*"]]
+
+Nothing shows up when I first used this directive. I found that I had to create a page for the tag for it to show up in pagestats.
+I would rather not find and create a page for every tag I have created or will create. Is there an easier way to create a list of tags?
+
+Thanks
+
+----
--- /dev/null
+The `pagetemplate` directive is supplied by the [[!iki plugins/pagetemplate desc=pagetemplate]] plugin.
+
+This directive allows a page to be created using a different wikitemplates.
+The page text is inserted into the template, so the template controls the
+overall look and feel of the wiki page. This is in contrast to the
+[[ikiwiki/directive/template]] directive, which allows inserting templates
+_into_ the body of a page.
+
+This directive can only reference templates that are already installed
+by the system administrator, typically into the
+`/usr/share/ikiwiki/templates` directory. Example:
+
+ \[[!pagetemplate template="my_fancy.tmpl"]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+[[!meta redir=/ikiwiki/directive/cutpaste]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `ping` directive is supplied by the [[!iki plugins/pinger desc=pinger]] plugin.
+
+This directive allows ikiwiki to be configured to hit a URL each time it
+updates the wiki. One way to use this is in conjunction with the [[!iki plugins/pingee desc=pingee]]
+plugin to set up a loosely coupled mirror network, or a branched version of
+a wiki. By pinging the mirror or branch each time the main wiki changes, it
+can be kept up-to-date.
+
+ \[[!ping from="http://mywiki.com/"
+ to="http://otherwiki.com/ikiwiki.cgi?do=ping"]]
+
+The "from" parameter must be identical to the url of the wiki that is doing
+the pinging. This is used to prevent ping loops.
+
+The "to" parameter is the url to ping. The example shows how to ping
+another ikiwiki instance.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `poll` directive is supplied by the [[!iki plugins/poll desc=poll]] plugin.
+
+This directive allows you to create online polls in the wiki. Here's an
+example use:
+
+ \[[!poll 0 "red" 0 "green" 0 "blue"]]
+
+The numbers indicate how many users voted for that choice. When a user
+votes for a choice in the poll, the page is modified and the number
+incremented.
+
+While some basic precautions are taken to prevent users from accidentially
+voting twice, this sort of poll should not be counted on to be very
+accurate; all the usual concerns about web based polling apply. Unless the
+page that the poll is in is locked, users can even edit the page and change
+the numbers!
+
+Parameters:
+
+* `open` - Whether voting is still open. Set to "no" to close the poll to
+ voting.
+* `total` - Show total number of votes at bottom of poll. Default is "yes".
+* `percent` - Whether to display percents. Default is "yes".
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `polygen` directive is supplied by the [[!iki plugins/polygen desc=polygen]] plugin.
+
+This directive allows inserting text generated by polygen into a wiki page.
+For example:
+
+ \[[!polygen grammar="genius"]]
+
+It's also possible to specify a starting nonterminal for the grammar by
+including `symbol="text"` in the directive.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `postsparkline` directive is supplied by the [[!iki plugins/postsparkline desc=postsparkline]] plugin.
+
+This directive uses the [[!iki plugins/sparkline desc=sparkline]] plugin to create a
+[[sparkline]] of statistics about a set of pages, such as posts to a blog.
+
+# examples
+
+ Post interval:
+ \[[!postsparkline pages="blog/* and !*/Discussion" max=100
+ formula=interval style=bar barwidth=2 barspacing=1 height=13]]
+
+ Posts per month this year:
+ \[[!postsparkline pages="blog/* and !*/Discussion" max=12
+ formula=permonth style=bar barwidth=2 barspacing=1 height=13]]
+
+# usage
+
+All options aside fron the `pages`, `max`, `formula`, `time`, and `color`
+options are the same as in [[sparkline]] directive.
+
+You don't need to specify any data points (though you can if you want to).
+Instead, data points are automatically generated based on the creation
+times of pages matched by the specified `pages` [[ikiwiki/PageSpec]]. A
+maximum of `max` data points will be generated.
+
+The `formula` parameter controls the formula used to generate data points.
+Available forumlae:
+
+* `interval` - The height of each point represents how long it has been
+ since the previous post.
+* `perday` - Each point represents a day; the height represents how
+ many posts were made that day.
+* `permonth` - Each point represents a month; the height represents how
+ many posts were made that month.
+* `peryear` - Each point represents a day; the height represents how
+ many posts were made that year.
+
+The `time` parameter has a default value of "ctime", since forumae use
+the creation times of pages by default. If you instead want
+them to use the modification times of pages, set it to "mtime".
+
+To change the color used to draw the sparkline, use the `color` parameter.
+For example, "color=red".
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `progress` directive is supplied by the [[!iki plugins/progress desc=progress]] plugin.
+
+This directive generates a progress bar.
+
+There are two possible parameter sets. The first is a single parameter
+"percent" which holds a percentage figure of how complete the progress bar is.
+
+The second possible set of parameters is a pair of [[ikiwiki/PageSpec]]s,
+`totalpages` and `donepages`. The directive counts the number of
+pages in each pagespec and shows the percentage of the total pages that are
+done.
+
+For example, to show what percentage of pages have
+discussion pages:
+
+ \[[!progress totalpages="* and !*/Discussion" donepages="*/Discussion"]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `shortcut` directive is supplied by the [[!iki plugins/shortcut desc=shortcut]] plugin.
+
+This directive allows external links to commonly linked to sites to be made
+more easily using shortcuts.
+
+The available shortcuts are defined on the [[shortcuts]] page in
+the wiki. The `shortcut` directive can only be used on that page.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `sparkline` directive is supplied by the [[!iki plugins/sparkline desc=sparkline]] plugin.
+
+This directive allows for embedding sparklines into wiki pages. A
+sparkline is a small word-size graphic chart, that is designed to be
+displayes alongside text.
+
+# examples
+
+ \[[!sparkline 1 3 5 -3 10 0 width=40 height=16
+ featurepoint="4,-3,red,3" featurepoint="5,10,green,3"]]
+
+This creates a simple line graph, graphing several points.
+It will be drawn 40 pixels wide and 16 pixels high. The high point in the
+line has a green marker, and the low point has a red marker.
+
+ \[[!sparkline 1 -1(red) 1 -1(red) 1 1 1 -1(red) -1(red) style=bar barwidth=2
+ barspacing=1 height=13]]
+
+This more complex example generates a bar graph.
+The bars are 2 pixels wide, and separated by one pixel, and the graph is 13
+pixels tall. Width is determined automatically for bar graphs. The points
+with negative values are colored red, instead of the default black.
+
+# usage
+
+The form for the data points is "x,y", or just "y" if the x values don't
+matter. Bar graphs can also add "(color)" to specify a color for that bar.
+
+The following named parameters are recognised. Most of these are the same
+as those used by the underlying sparkline library, which is documented in
+more detail in [its wiki](http://sparkline.wikispaces.com/usage).
+
+* `style` - Either "line" (the default) or "bar".
+* `width` - Width of the graph in pixels. Only needed for line graphs.
+* `height` - Height of the graph in pixels. Defaults to 16.
+* `barwidth` - Width of bars in a bar graph. Default is 1 pixel.
+* `barspacing` - Spacing between bars in a bar graph, in pixels. Default is
+ 1 pixel.
+* `ymin`, `ymax` - Minimum and maximum values for the Y axis. This is
+ normally calculated automatically, but can be explicitly specified to get
+ the same values for multiple related graphs.
+* `featurepoint` - Adds a circular marker to a line graph, with optional
+ text. This can be used to label significant points.
+
+ The value is a comma-delimited list of parameters specifying the feature
+ point: X value, Y value, color name, circle diameter, text (optional),
+ and text location (optional). Example: `featurepoint="3,5,blue,3"`
+
+ Available values for the text location are: "top", "right", "bottom", and
+ "left".
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `table` directive is supplied by the [[!iki plugins/table desc=table]] plugin.
+
+This directive can build HTML tables from data in CSV (comma-separated values)
+or DSV (delimiter-separated values) format.
+
+## examples
+
+ \[[!table data="""
+ Customer|Amount
+ Fulanito|134,34
+ Menganito|234,56
+ Menganito|234,56
+ """]]
+
+ \[[!table class="book_record" format=csv file="data/books/record1"]]
+
+In this second example the `record1` page should be similar to:
+
+ "Title","Perl Best Practices"
+ "Author","Damian Conway"
+ "Publisher","O’Reilly"
+
+To make a cell span multiple columns, follow it with one or more empty
+cells. For example:
+
+ \[[!table data="""
+ left||right|
+ a|b|c|d
+ this cell spans 4 columns|||
+ """]]
+
+## usage
+
+* `data` - Values for the table.
+* `file` - A file in the wiki containing the data.
+* `format` - The format of the data, either "csv", "dsv", or "auto"
+ (the default).
+* `delimiter` - The character used to separate fields. By default,
+ DSV format uses a pipe (`|`), and CSV uses a comma (`,`).
+* `class` - A CSS class for the table html element.
+* `header` - By default, or if set to "row", the first data line is used
+ as the table header. Set it to "no" to make a table without a header, or
+ "column" to make the first column be the header.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `tag` and `taglink` directives are supplied by the [[!iki plugins/tag desc=tag]] plugin.
+
+These directives allow tagging pages. List tags as follows:
+
+ \[[!tag tech life linux]]
+
+The tags work the same as if you had put a (hidden) [[ikiwiki/WikiLink]] on
+the page for each tag, so you can use a [[ikiwiki/PageSpec]] match all
+pages that are tagged with a given tag, for example. The tags will also
+show up on blog entries and at the bottom of the tagged pages, as well as
+in RSS and Atom feeds.
+
+If you want a visible [[ikiwiki/WikiLink]] along with the tag, use taglink
+instead:
+
+ \[[!taglink foo]]
+ \[[!taglink tagged_as_foo|foo]]
+
+Note that if the wiki is configured to use a tagbase, then the tags will be
+located under a base directory, such as "tags/". This is a useful way to
+avoid having to write the full path to tags, if you want to keep them
+grouped together out of the way.
+
+Bear in mind that specifying a tagbase means you will need to incorporate it
+into the `link()` [[ikiwiki/PageSpec]] you use: e.g., if your tagbase is
+`tag`, you would match pages tagged "foo" with `link(tag/foo)`.
+
+If you want to override the tagbase for a particular tag, you can use
+something like this:
+
+ \[[!tag ./foo]]
+ \[[!taglink /foo]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+[[!meta redir=/ikiwiki/directive/tag]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `template` directive is supplied by the [[!iki plugins/template desc=template]] plugin.
+
+[[Templates]] are files that can be filled out and inserted into pages in the
+wiki, by using the template directive. The directive has an `id` parameter
+that identifies the template to use. The remaining parameters are used to
+fill out the template.
+
+Example:
+
+ \[[!template id=note text="""Here is the text to insert into my note."""]]
+
+This fills out the `note` template, filling in the `text` field with
+the specified value, and inserts the result into the page.
+
+For a list of available templates, and details about how to create more,
+see the [[templates]] page.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `testpagespec` directive is supplied by the [[!iki plugins/testpagespec desc=testpagespec]] plugin.
+
+This directive allows testing a [[ikiwiki/PageSpec]] to see if it matches a
+page, and to see the part that matches, or causes the match to fail.
+
+Example uses:
+
+ \[[!testpagespec pagespec="foopage and barpage" match="foopage"]]
+
+This will print out something like "no match: barpage does not match
+foopage", highlighting which part of the [[ikiwiki/PageSpec]] is causing
+the match to fail.
+
+ \[[!testpagespec pagespec="foopage or !bar*" match="barpage"]]
+
+This will print out something like "no match: bar* matches barpage", since
+the part of the [[ikiwiki/PageSpec]] that fails is this negated match.
+
+ \[[!testpagespec pagespec="foopage or barpage" match="barpage"]]
+
+This will print out something like "match: barpage matches barpage",
+indicating the part of the [[ikiwiki/PageSpec]] that caused it to match.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+How does one test a user identity? I tried "pagename and user(username) for the match, and had a "no user specified" error.
+
+> You can't test them with this directive, because such pagespecs test to
+> see if logged in user, who is performing some action, matches. When the
+> page with the directive is built, the concept of a user being logged in
+> doesn't really apply. --[[Joey]]
--- /dev/null
+The `teximg` directive is supplied by the [[!iki plugins/teximg desc=teximg]] plugin.
+
+This directive renders LaTeX formulas into images.
+
+## examples
+
+ \[[!teximg code="\frac{1}{2}"]]
+ \[[!teximg code="E = - \frac{Z^2 \cdot \mu \cdot e^4}{32\pi^2 \epsilon_0^2 \hbar^2 n^2}" ]]
+
+To scale the image, use height=x:
+
+ \[[!teximg code="\frac{1}{2}" height="17"]]
+ \[[!teximg code="\frac{1}{2}" height="8"]]
+
+If no height is chosen the default height 12 is used. Valid heights are: 8, 9,
+10, 11, 12, 14, 17, 20. If another height is entered, the closest available
+height is used.
+
+To add an alt text to the image, use alt="text":
+
+ \[[!teximg code="\frac{1}{2}" alt="1/2"]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `toc` directive is supplied by the [[!iki plugins/toc desc=toc]] plugin.
+
+Add a table of contents to a page:
+
+ \[[!toc ]]
+
+The table of contents will be automatically generated based on the
+headers of the page. By default only the largest headers present on the
+page will be shown; to control how many levels of headers are shown, use
+the `levels` parameter:
+
+ \[[!toc levels=2]]
+
+The toc directive will take the level of the first header as the topmost
+level, even if there are higher levels seen later in the file.
+
+The table of contents will be created as an ordered list. If you want
+an unordered list instead, you can change the list-style in your local
+style sheet.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `toggle` and `toggleable` directives are supplied by the [[!iki plugins/toggle desc=toggle]] plugin.
+
+With these directives you can create links on pages that, when clicked, toggle
+display of other parts of the page.
+
+It uses javascript to accomplish this; browsers without javascript will
+always see the full page content.
+
+Example use:
+
+ \[[!toggle id="ipsum" text="show"]]
+
+ \[[!toggleable id="ipsum" text="""
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
+ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
+ ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
+ aliquip ex ea commodo consequat.
+
+ [[!toggle id="ipsum" text="hide"]]
+ """]]
+
+Note that you can include wiki markup in the toggleable text,
+including even additional toggles, as shown in the above example.
+
+Also, the toggle and the togglable definitions do not need to be next to
+each other, but can be located anywhere on the page. There can also be
+mutiple toggles that all toggle a single togglable.
+
+The id has a default value of "default", so can be omitted in simple cases.
+
+If you'd like a toggleable to be displayed by default, and toggle to
+hidden, then pass a parameter "open=yes" when setting up the toggleable.
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+[[!meta redir=/ikiwiki/directive/toggle]]
+
+[[!meta robots="noindex, follow"]]
--- /dev/null
+The `version` directive is supplied by the [[!iki plugins/version desc=version]] plugin.
+
+This directive allows inserting the version of ikiwiki onto a page.
+
+Whenever ikiwiki is upgraded to a new version, the page will be rebuilt,
+updating the version number.
+
+Use is simple:
+
+ \[[!version ]]
+
+[[!meta robots="noindex, follow"]]
Leave blank lines between paragraphs.
-You can \**emphasise*\* or \*\***strongly emphasise**\*\* text by placing it
+You can *\*emphasise\** or **\*\*strongly emphasise\*\*** text by placing it
in single or double asterisks.
To create a list, start each line with an asterisk:
\[[!wikipedia War\_of\_1812]]
"""]]
+[[!if test="enabled(template) and templates" then="""
+* Create and fill out [[templates]] for repeated chunks of
+ parameterized wiki text.
+"""]]
+
+* Insert various [[directives|directive]] onto a page to perform useful
+ actions.
+[[!if test="enabled(toc) or enabled(meta) or enabled(inline)" then="""
+ For example, you can:
+"""]]
+
[[!if test="enabled(toc)" then="""
-* Add a table of contents to a page:
+ * Add a table of contents to a page:
- \[[!toc ]]
+ \[[!toc]]
"""]]
[[!if test="enabled(meta)" then="""
-* Change the title of a page:
+ * Change the title of a page:
\[[!meta title="full page title"]]
"""]]
-[[!if test="enabled(inline) and blog" then="""
-* Create a [[blog]] by inlining a set of pages:
+[[!if test="enabled(inline)" then="""
+ * Create a blog by inlining a set of pages:
\[[!inline pages="blog/*"]]
"""]]
-[[!if test="enabled(template) and templates" then="""
-* Create and fill out [[templates]] for repeated chunks of
- parameterized wiki text.
+[[!if test="enabled(listdirectives)" then="""
+ Full list of [[directives|directive]] enabled for this wiki:
+ [[!listdirectives ]]
"""]]
email messages. It is the markup language used by this wiki by default.
For documentation about the markdown syntax, see [[formatting]] and
-[Markdown: syntax](http://daringfireball.net/projects/markdown/syntax). A
-[markdown mode](http://jblevins.org/projects/markdown-mode/) for
-emacs can help in editing.
+[Markdown: syntax](http://daringfireball.net/projects/markdown/syntax).
-Note that [[WikiLink]]s and [[PreProcessorDirective]]s are not part of the
-markdown syntax, and are the only bit of markup that this wiki handles
-internally.
+Note that [[WikiLinks|WikiLink]] and [[directives|directive]] are not part
+of the markdown syntax, and are the only bit of markup that this wiki
+handles internally.
* [Videntity](http://videntity.org/)
* [LiveJournal](http://www.livejournal.com/openid/)
* [TrustBearer](https://openid.trustbearer.com/)
-* or any of the [many others out there](http://openiddirectory.com/openid-providers-c-1.html).
+* or any of the [many others out there](http://openiddirectory.com/openid-providers-c-1.html)
Your OpenID is the URL that you are given when you sign up.
[[!if test="enabled(openid)" then="""
* and !SandBox and !*/Discussion
-Some more elaborate limits can be added to what matches using any of these
-functions:
+Some more elaborate limits can be added to what matches using these functions:
-* "`link(page)`" - match only pages that link to a given page (or glob)
-* "`backlink(page)`" - match only pages that a given page links to
-* "`creation_month(month)`" - match only pages created on the given month
+* "`link(page)`" - matches only pages that link to a given page (or glob)
+* "`tagged(tag)`" - matches pages that are tagged or link to the given tag (or
+ tags matched by a glob)
+* "`backlink(page)`" - matches only pages that a given page links to
+* "`creation_month(month)`" - matches only pages created on the given month
* "`creation_day(mday)`" - or day of the month
* "`creation_year(year)`" - or year
-* "`created_after(page)`" - match only pages created after the given page
+* "`created_after(page)`" - matches only pages created after the given page
was created
-* "`created_before(page)`" - match only pages created before the given page
+* "`created_before(page)`" - matches only pages created before the given page
was created
-* "`glob(someglob)`" - match pages that match the given glob. Just writing
+* "`glob(someglob)`" - matches pages that match the given glob. Just writing
the glob by itself is actually a shorthand for this function.
* "`internal(glob)`" - like `glob()`, but matches even internal-use
pages that globs do not usually match.
* "`title(glob)`", "`author(glob)`", "`authorurl(glob)`",
"`license(glob)`", "`copyright(glob)`" - match pages that have the given
metadata, matching the specified glob.
+* "`user(username)`" - tests whether a modification is being made by a
+ user with the specified username. If openid is enabled, an openid can also
+ be put here.
+* "`admin()`" - tests whether a modification is being made by one of the
+ wiki admins.
+* "`ip(address)`" - tests whether a modification is being made from the
+ specified IP address.
+* "`postcomment(glob)`" - matches only when comments are being
+ posted to a page matching the specified glob
For example, to match all pages in a blog that link to the page about music
and were written in 2005:
grouping. For example, to match pages in a blog that are tagged with either
of two tags, use:
- blog/* and (link(tag/foo) or link(tag/bar))
+ blog/* and (tagged(foo) or tagged(bar))
Note that page names in PageSpecs are matched against the absolute
filenames of the pages in the wiki, so a pagespec "foo" used on page
"a/b" will not match a page named "a/foo" or "a/b/foo". To match
relative to the directory of the page containing the pagespec, you can
use "./". For example, "./foo" on page "a/b" matches page "a/foo".
-
-## Old syntax
-
-The old PageSpec syntax was called a "GlobList", and worked differently in
-two ways:
-
-1. "and" and "or" were not used; any page matching any item from the list
- matched.
-2. If an item was prefixed with "`!`", then no page matching that item
- matched, even if it matched an earlier list item.
-
-For example, here is the old way to match all pages except for the SandBox
-and Discussion pages:
-
- * !SandBox !*/Discussion
-
-Using this old syntax is still supported. However, the old syntax is
-deprecated and will be removed at some point, and using the new syntax is
-recommended.
else="This wiki has attachments **disabled**."]]
If attachments are enabled, the wiki admin can control what types of
-attachments will be accepted, by entering a [[ikiwiki/PageSpec]] in the
-"Allowed Attachments" field of their preferences page.
+attachments will be accepted, via the `allowed_attachments`
+configuration setting.
For example, to limit arbitrary files to 50 kilobytes, but allow
larger mp3 files to be uploaded by joey into a specific directory, and
-check all attachments for virii, something like this could be used:
+check all attachments for viruses, something like this could be used:
virusfree() and ((user(joey) and podcast/*.mp3 and mimetype(audio/mpeg) and maxsize(15mb)) or (!ispage() and maxsize(50kb)))
-The regular [[ikiwiki/PageSpec]] syntax is expanded with thw following
+The regular [[ikiwiki/PageSpec]] syntax is expanded with the following
additional tests:
-* maxsize(size)
-
- Tests whether the attachment is no larger than the specified size.
- The size defaults to being in bytes, but "kb", "mb", "gb" etc can be
- used to specify the units.
+* "`maxsize(size)`" - tests whether the attachment is no larger than the
+ specified size. The size defaults to being in bytes, but "kb", "mb", "gb"
+ etc can be used to specify the units.
-* minsize(size)
-
- Tests whether the attachment is no smaller than the specified size.
-
-* ispage()
+* "`minsize(size)`" - tests whether the attachment is no smaller than the
+ specified size.
- Tests whether the attachment will be treated by ikiwiki as a wiki page.
- (Ie, if it has an extension of ".mdwn", or of any other enabled page
- format).
+* "`ispage()`" - tests whether the attachment will be treated by ikiwiki as a
+ wiki page. (Ie, if it has an extension of ".mdwn", or of any other enabled
+ page format).
So, if you don't want to allow wiki pages to be uploaded as attachments,
use `!ispage()` ; if you only want to allow wiki pages to be uploaded
as attachments, use `ispage()`.
-* user(username)
-
- Tests whether the attachment is being uploaded by a user with the
- specified username. If openid is enabled, an openid can also be put here.
-
-* ip(address)
-
- Tests whether the attacment is being uploaded from the specified IP
- address.
-
-* mimetype(foo/bar)
-
- This checks the MIME type of the attachment. You can include a glob
- in the type, for example `mimetype(image/*)`.
-
-* virusfree()
+* "`mimetype(foo/bar)`" - checks the MIME type of the attachment. You can
+ include a glob in the type, for example `mimetype(image/*)`.
- Checks the attachment with an antiviral program.
+* "`virusfree()`" - checks the attachment with an antiviral program.
--- /dev/null
+Would it be possible to factor out this pagespec
+code so that other plugins can use it without enabling attachments?
+I am interested for [[todo/mbox]] --[[DavidBremner]]
+
+> I can split out all of them except for `ip()` and `user()` easily. I
+> have just changed the code so the rest will test the existing source file
+> is no other filename is specified. Do you have any reason to want to
+> check ip addresses and user names? Not sure what to call the plugin, but
+> breaking it out is easy enough. --[[Joey]]
+
+>> I don't think `ip()` and `user()` necessarily make sense for a mail box
+>> that is already on the disk, so no, I don't think I'll miss
+>> them. --[[DavidBremner]]
+
+>>> Done, [[plugins/filecheck]] --[[Joey]]
> I don't see why that wouldn't work. Can I download the source to your
> wiki from somewhere to investigate? --[[Joey]]
+
+----
+
+Should negation work with user(), with locked_pages in setup? I
+experimented with setting locked_pages => 'user(someuser)' and was able to
+edit as a different user. However, setting locked_pages =>
+'!user(someuser)' doesn't seem to allow edits for only 'someuser' - it
+locks out all users.
+
+> Negation works with anything in any PageSpec. I tested the case you
+> describe, and a negated pagespec worked for me; all users except the
+> listed user (and except wiki admins of course) were locked out.
+> --[[Joey]]
+
+>> It must be a local problem, then, cause I've tried it with two separate
+>> machines. Both are running the most recent release of ikiwiki in
+>> pkgsrc - 2.66. Perhaps an update to a newer version would solve the issue.
+
+----
+
+Is there a way to refer to all subpages of the current page, if the name of the
+current page is not known (i.e. the pagespec is used in a template)? The ./ syntax
+does not seem suitable for this, as
+
+> \[[!map pages="./*"]]
+
+also lists the current page and all its siblings.
--- /dev/null
+[[!if test="enabled(po)"
+ then="This wiki has po support **enabled**."
+ else="This wiki has po support **disabled**."]]
+
+If the [[!iki plugins/po desc=po]] plugin is enabled, the regular
+[[ikiwiki/PageSpec]] syntax is expanded with the following additional
+tests that can be used to improve user navigation in a multi-lingual
+wiki:
+
+* "`lang(LL)`" - tests whether a page is written in the language
+ specified as a ISO639-1 (two-letter) language code.
+* "`currentlang()`" - tests whether a page is written in the same
+ language as the current page.
+
+Note that every non-po page is considered to be written in
+`po_master_language`, as specified in `ikiwiki.setup`.
+++ /dev/null
-[[!meta robots="noindex, follow"]]
-Preprocessor directives are similar to a [[WikiLink]] in form, except they
-begin with `!` and may contain parameters. The general form is:
-
- \[[!directive param="value" param="value"]]
-
-This gets expanded before the rest of the page is processed, and can be used
-to transform the page in various ways.
-
-The quotes around values can be omitted if the value is a simple word.
-Also, some directives may use parameters without values, for example:
-
- \[[!tag foo]]
-
-A preprocessor directive does not need to all be on one line, it can be
-wrapped to multiple lines if you like:
-
- \[[!directive foo="baldersnatch"
- bar="supercalifragalisticexpealadocious" baz=11]]
-
-Also, multiple lines of *quoted* text can be used for a value.
-To allow quote marks inside the quoted text, delimit the block
-of text with triple-quotes:
-
- \[[!directive text="""
- 1. "foo"
- 2. "bar"
- 3. "baz"
- """]]
-
-ikiwiki also has an older syntax for preprocessor directives, which requires a
-space in directives to distinguish them from [[wikilinks|wikilink]]. This
-syntax has several disadvantages: it requires a space after directives with no
-parameters (such as `\[[pagecount ]]`), and it prohibits spaces in
-[[wikilinks|wikilink]]. ikiwiki now provides the `!`-prefixed syntax shown
-above as the preferred alternative. However, ikiwiki still supports wikis
-using the older syntax, if the `prefix_directives` option is not enabled.
-For backward compatibility with existing wikis, this option currently
-defaults to off, so ikiwiki supports the old syntax.
else="This wiki has searching **disabled**."]]
If searching is enabled, you can enter search terms in the search field,
-as you'd expect. There are a few special things you can do to constuct
+as you'd expect. There are a few special things you can do to construct
more powerful searches.
* To match a phrase, enclose it in double quotes.
page, but the link will appear like this: [[foo_bar|SandBox]].
To link to an anchor inside a page, you can use something like
-`\[[WikiLink#foo]]`
+`\[[WikiLink#foo]]` .
-## Preprocessor directives and wikilinks
+## Directives and WikiLinks
ikiwiki has two syntaxes for
-[[preprocessor_directives|PreprocessorDirective]]. The older syntax
-used spaces to distinguish between preprocessor directives and
+[[directives|directive]]. The older syntax
+used spaces to distinguish between directives and
wikilinks; as a result, with that syntax in use, you cannot use spaces
in WikiLinks, and must replace spaces with underscores. The newer
syntax, enabled with the `prefix_directives` option in an ikiwiki
-# Creating an anchor in Markdown
+# Creating an [[anchor]] in Markdown
-Is it a native Markdown "tag" for creating an anchor? Unfortunately,
+Is it a native Markdown "tag" for creating an [[anchor]]? Unfortunately,
I haven't any information about it at
[Markdown syntax](http://daringfireball.net/projects/markdown/syntax) page.
--[[Paweł|ptecza]]
> No such syntax exists in markdown. ikiwiki could certainly have a
-> [[preprocessor_directive|preprocessordirective]] for it, though.
+> [[preprocessor_directive|directive]] for it, though.
> --[[JoshTriplett]]
->> [[tag wishlist]]
+>> [[!tag wishlist]]
>> I'd like to implement such a thing. Joey, what is this supposed to look like?
>> `\[[anchor WHATEVER]]`? --[[tschwinge]]
this doesn't work, so I had to resort to using `\[[foo/bar]]` instead.
--[[tschwinge]]
+> I believe, that doesn't entirely solve the problem. Just assume, your hierarchy is `/foo/bar/foo/bar`.
+
+> How do you access from the page `/foo/bar/foo/bar` the `/foo/bar` and not `/foo/bar/foo/bar`?
+
+> Do we have a way to implement `\[[../..]]` or `\[[/foo/bar]]`?
+
+> Even worse, trying to link from `/foo/bar` to `/foo/bar/foo/bar` ... this will probably need `\[[./foo/bar]]` --[[Jan|jwalzer]]
+
+>> There is no ".." syntax in wikilinks, but if the link begins with "/" it
+>> is rooted at the top of the wiki, as documented in
+>> [[subpage/linkingrules]]. Therefore, every example page name you listed
+>> above will work unchanged as a wikilink to that page! --[[Joey]]
+
----
How do I make images clickable? The obvious guess, \[[foo.png|/index]], doesn't work. --[[sabr]]
> You can do it using the img plugin. The syntax you suggested would be ambiguous,
> as there's no way to tell if the text is meant to be an image or displayed as-is.
> --[[Joey]]
+
+----
+
+Is it possible to refer to a page, say \[[foobar]], such that the link text is taken from foobar's title [[directive/meta]] tag? --Peter
+
+> Not yet. :-) Any suggestion for a syntax for it? Maybe something like \[[|foobar]] ? --[[Joey]]
+
+I like your suggestion because it's short and conscise. However, it would be nice to be able to refer to more or less arbitrary meta tags in links, not just "title". To do that, the link needs two parameters: the page name and the tag name, i.e. \[[pagename!metatag]]. Any sufficiently weird separater can be used instead of '!', of course. I like \[[pagename->metatag]], too, because it reminds me of accessing a data member of a structure (which is what referencing a meta tag is, really). --Peter
-Projects
-========
+Projects & Organizations
+========================
* [This wiki](http://ikiwiki.info) (of course!)
-* [UK Software Patents info page](http://www.softwarepatents.co.uk/)
+* The [GNU Hurd](http://www.gnu.org/software/hurd/)
+* [DragonFly BSD](http://www.dragonflybsd.org/)
+* [Monotone](http://monotone.ca/wiki/FrontPage/)
+* The [Free Software Foundation](http://fsf.org) uses it for their internal wiki, with subversion.
+* The [cairo graphics library](http://cairographics.org/) website.
+* The [Portland State Aerospace Society](http://psas.pdx.edu) website. Converted from a combination of TWiki and MoinMoin to ikiwiki, including full history ([[rcs/Git]] backend).
* [Planet Debian upstream](http://updo.debian.net/)
-* The [ion window manager homepage](http://modeemi.fi/~tuomov/ion/)
* [Debian Mentors wiki](http://jameswestby.net/mentors/)
-* [LinuxWorld.com's monkey.linuxworld.com contributor wiki](http://monkey.linuxworld.com/) ([[rcs/Git]] backend)
* The [Sparse wiki](http://kernel.org/pub/linux/kernel/people/josh/sparse).
* [The BSD Associate Admin Book Project](http://bsdwiki.reedmedia.net/)
* The [maildirman wiki](http://svcs.cs.pdx.edu/maildirman)
* [Braawi Ltd](http://braawi.com/) and the community site [Braawi.org](http://braawi.org/)
* [Webconverger](http://webconverger.org/) (a Web only linux distribution) with a [blog](http://webconverger.org/blog/)
* [debian-community.org](http://debian-community.org/)
-* The [cairo graphics library](http://cairographics.org/) website.
-* The [Portland State Aerospace Society](http://psas.pdx.edu) website. Converted from a combination of TWiki and MoinMoin to ikiwiki, including full history ([[rcs/Git]] backend).
* [DebTorrent](http://debtorrent.alioth.debian.org)
* The [netconf project](http://netconf.alioth.debian.org)
* The [Debian Packaging Handbook project](http://packaging-handbook.alioth.debian.org/wiki/)
* The [libkdtree project](http://libkdtree.alioth.debian.org)
* The [pcc](http://pcc.ludd.ltu.se/) (Portable C Compiler) project. (Simple rcs backend)
-* [The TOVA Company](http://www.tovatest.com) public site. We also use it for internal documentation and issue tracking, all with a [[rcs/Git]] backend.
+* [The TOVA Company](http://www.tovatest.com) public site. We also use it for internal documentation and issue tracking, all with a [[rcs/Git]] backend.
* Technical support websites for [Homebase](http://support.homebase.dk) and [Kaospilotene](http://support.kaospilot.no) (each with [source](http://source.homebase.dk/) [provided](http://source.kaospilot.no/))
* [CampusGrün Hamburg](http://www.campusgruen.org/)
* The [awesome window manager homepage](http://awesome.naquadah.org/)
* [Enemies of Carlotta](http://www.e-o-c.org/)
* [vcs-pkg](http://vcs-pkg.org)
* [vcs-home](http://vcs-home.madduck.net)
-* [GNU Hurd wiki](http://www.bddebian.com/~wiki/)
* [Query Object Framework](http://qof.alioth.debian.org/)
* [Estron - Object Relational Mapping interpreter](http://estron.alioth.debian.org/)
* [Public Domain collection of Debian related tips & tricks](http://dabase.com/tips/) - please add any tips too
* [Finnish Debian community](http://debian.fi)
+* [INCL intranuclear cascade and ABLA evaporation/fission](http://www.cs.helsinki.fi/u/kaitanie/incl/)
+* [dist-bugs](http://dist-bugs.kitenet.net/)
+* [Chaos Computer Club Düsseldorf](https://www.chaosdorf.de)
+* [monkeysphere](http://web.monkeysphere.info/)
+* [The Walden Effect](http://www.waldeneffect.org/)
+* The support pages for [Trinity Centre for High Performance Computing](http://www.tchpc.tcd.ie/support/)
+* [St Hugh of Lincoln Catholic Primary School in Surrey](http://www.sthugh-of-lincoln.surrey.sch.uk/)
+* [Pigro Network](http://www.pigro.net) is running a hg based ikiwiki. (And provides ikiwiki hosting for $10/m.)
+* [Cosin Homepage](http://cosin.ch) uses an Ikiwiki with a subversion repository.
+* [Bosco Free Orienteering Software](http://bosco.durcheinandertal.ch)
+* [MIT Student Information Processing Board](http://sipb.mit.edu/)
Personal sites and blogs
========================
* [madduck's (new) homepage](http://madduck.net)
* [Olivier Berger's professional homepage](http://www-public.it-sudparis.eu/~berger_o/)
* [Andrey Tarantsov's homepage](http://www.tarantsov.com/)
+* [Don Marti's blog](http://zgp.org/~dmarti/)
+* [[users/Jon]]'s [homepage](http://jmtd.net/)
+* [[xma]] is using ikiwiki (<http://maillard.mobi/~xma/>)
+* [[JanWalzer|jwalzer]]'s [homepage](http://wa.lzer.net/) -- Work in Progress
+* [[Adam_Trickett|ajt]]'s home intranet/sanbox system ([Internet site & blog](http://www.iredale.net/) -- not ikiwiki yet)
+* [[Simon_McVittie|smcv]]'s [website](http://www.pseudorandom.co.uk/) and
+ [blog](http://smcv.pseudorandom.co.uk/)
+* Svend's [website](http://www.ciffer.net/~svend/) and [blog](http://www.ciffer.net/~svend/blog/)
+* [muammar's site](http://muammar.me)
+* [Per Bothner's blog](http://per.bothner.com/blog/)
+* [Bernd Zeimetz (bzed)](http://bzed.de/)
+* [Gaudenz Steinlin](http://gaudenz.durcheinandertal.ch)
+* [Simon Kjika'qawej C.](http://simonraven.kisikew.org/) - several other sites, too.
+* [NeoCarz Wiki](http://www.neocarz.com/wiki/) Yes - its actually Ikiwiki behind that! I'm using Nginx and XSL to transform the ikiwiki renderings thanks to the valid XHTML output of ikiwiki. Great work Joey!!
+* [Natalian - Kai Hendry's personal blog](http://natalian.org/)
+* [Mick Pollard aka \_lunix_ - Personal sysadmin blog and wiki](http://www.lunix.com.au)
+* [tumashu's page](http://tumashu.github.com) This is my personal site in github created with ikiwiki and only a page,you can get the [source](http://github.com/tumashu/tumashu/tree/master)
+* [Skirv's Wiki](http://wiki.killfile.org) - formerly Skirv's Homepage
+* [Jimmy Tang - personal blog and wiki](http://www.sgenomics.org/~jtang)
Please feel free to add your own ikiwiki site!
-See also: [Debian ikiwiki popcon graph](http://people.debian.org/~igloo/popcon-graphs/index.php?packages=ikiwiki)
+See also: [Debian ikiwiki popcon graph](http://qa.debian.org/popcon.php?package=ikiwiki)
and [google search for ikiwiki powered sites](http://www.google.com/search?q=%22powered%20by%20ikiwiki%22).
-While nothing makes me happier than knowing that ikiwiki has happy users, dropping some change in the [[TipJar]] is a nice way to show extra appreciation.
+While nothing makes me happier than knowing that ikiwiki has happy users,
+dropping some change in the [[TipJar]] is a nice way to show extra
+appreciation.
Thanks for the reply Joey! ikiwiki is a fantastic wiki complier, though I do
not have my own machine momentarily, i will pay close attention to its development.
Hopefully I will be one of the ikiwiki users one day :) cheers --[[Chao]]
+
+----
+
+Are there automated hosting sites for ikiwiki yet? If you know one, can you add one in a new section on [[ikiwikiusers]] please? If you don't know any and you're willing to pay to set one up (shouldn't be much more expensive than a single ikiwiki IMO), [contact me](http://www.ttllp.co.uk/contact.html) and let's talk. -- MJR
suitable for publishing on a website. Ikiwiki stores pages and history in a
[[revision_control_system|rcs]] such as [[Subversion|rcs/svn]] or [[rcs/Git]].
There are many other [[features]], including support for
-[[blogging|ikiwiki/blog]], as well as a large array of [[plugins]].
+[[blogging|blog]], as well as a large array of [[plugins]].
-[[template id=links]]
+[[!template id=links]]
## using ikiwiki
All wikis are supposed to have a [[SandBox]], so this one does too.
This site generally runs the latest release of ikiwiki; currently, it runs
-ikiwiki [[version ]].
+ikiwiki [[!version ]].
## developer resources
Note that for more formal bug reports or todo items, you can also edit the
[[bugs]] and [[todo]] pages.
-[[toc ]]
+[[!toc ]]
# Installation/Setup questions
>Ubuntu Hardy Heron has a debian package now, but that does not work either.
> --Dirk 22Apr2008
+> This might be related to [Text::Markdown bug #37297](http://rt.cpan.org/Public/Bug/Display.html?id=37297).--ChapmanFlack 9Jul2008
+
----
# Installation of selected docs (html)
perl dependencies installed because that's well documented in the perl world,
but I don't know how to tell ikiwiki to install somewhere other than / --BrianWilson
-> Checkout the tips section for [[tips/SharedHosting]]. It should do the trick. --MattReynolds
+> Checkout the tips section for [[tips/DreamHost]]. It should do the trick. --MattReynolds
----
> Jamey Sharp and I have a set of scripts in progress to convert other wikis to ikiwiki, including history, so that we can migrate a few of our wikis. We already have support for migrating MoinMoin wikis to ikiwiki, including conversion of the entire history to Git. We used this to convert the [XCB wiki](http://xcb.freedesktop.org/wiki/) to ikiwiki; until we finalize the conversion and put the new wiki in place of the old one, you can browse the converted result at <http://xcb.freedesktop.org/ikiwiki>. We already plan to add support for TWiki (including history, since you can just run parsecvs on the TWiki RCS files to get Git), so that we can convert the [Portland State Aerospace Society wiki](http://psas.pdx.edu) (currently in Moin, but with much of its history in TWiki, and with many of its pages still in TWiki format using Jamey's TWiki format for MoinMoin).
>
-> Our scripts convert by way of HTML, using portions of the source wiki's code to render as HTML (with some additional code to do things like translate MoinMoin's `\[[TableOfContents]]` to ikiwiki's `\[[toc ]]`), and then using a modified [[cpan HTML::WikiConverter]] to turn this into markdown and ikiwiki. This produces quite satisfactory results, apart from things that don't have any markdown equivalent and thus remain HTML, such as tables and definition lists. Conversion of the history occurs by first using another script we wrote to translate MoinMoin history to Git, then using our git-map script to map a transformation over the Git history.
+> Our scripts convert by way of HTML, using portions of the source wiki's code to render as HTML (with some additional code to do things like translate MoinMoin's `\[[TableOfContents]]` to ikiwiki's `\[[!toc ]]`), and then using a modified [[!cpan HTML::WikiConverter]] to turn this into markdown and ikiwiki. This produces quite satisfactory results, apart from things that don't have any markdown equivalent and thus remain HTML, such as tables and definition lists. Conversion of the history occurs by first using another script we wrote to translate MoinMoin history to Git, then using our git-map script to map a transformation over the Git history.
>
> We will post the scripts as soon as we have them complete enough to convert our wikis.
>
>>> It appears the scripts were never posted? I recently imported my Mediawiki site into Iki. If it helps, my notes are here: <http://iki.u32.net/Mediawiki_Conversion> --[[sabr]]
+>>>>> The scripts have been posted now, see [[joshtriplett]]'s user page,
+>>>>> and I've pulled together all ways I can find to [[convert]] other
+>>>>> systems into ikiwiki. --[[Joey]]
+
----
# LaTeX support?
> The default `wiki_file_regexp` matches filenames containing only
> `[-[:alnum:]_.:/+]`
>
-> The IkiWiki::titlepage() function will convert freeform text to a valid
+> The titlepage() function will convert freeform text to a valid
> page name. See [[todo/should_use_a_standard_encoding_for_utf_chars_in_filenames]]
> for an example. --[[Joey]]
--- /dev/null
+# OpenID discussion
+
+## No return_to in OpenID server
+
+Hi, there's no return_to from a designated OpenID server page, specs requires (I think a "should" or "must", can't recall exact wording) that it redirects back to the RP, in order to complete the registration and authentication. Unless I'm missing something, and the doc is incomplete, I'd consider this a bug. I don't expect to be of much use WRT coming up with a patch, but I'm willing to test ;-) .
+
+> If this is a bug, could you please explain:
+>
+> * What happens when the bug occurs?
+> * How can one reproduce the bug?
+>
+> PS, please file bugs under [[bugs]] in future. --[[Joey]]
+
+>> Oops, my bad, didn't know that existed at the time I wrote this.
+>>
+>> What happened is that the process wouldn't complete, therefore I couldn't login with my OpenID.
+>>
+>> reproducibility: every time
+>>
+>> Should probably move this page, eh? ;)
+>> I'd do that, but I dunno know other than using the SCM backend in question....
+
+Here's some actual output (with my OpenID URL stripped out):
+
+do=postsignin&oic.time=1238224497-1450566d93097caa707f&openid.assoc_handle=%7BHMAC-SHA1%7D%7B49cdce76%7D%7BBhuXXw%3D%3D%7D&openid.identity=|<==== MY OPENID URL GOES HERE ====>|&openid.mode=id_res&openid.op_endpoint=http%3A%2F%2Fwww.myopenid.com%2Fserver&openid.response_nonce=2009-03-28T07%3A15%3A02ZDUFmG3&openid.return_to=http%3A%2F%2Fsimonraven.kisikew.org%2Fbin%2Fikiwiki.cgi%3Fdo%3Dpostsignin%26oic.time%3D1238224497-1450566d93097caa707f&openid.sig=E51Xh6Gnjku%2B0se57qCyhHbT5QY%3D&openid.signed=assoc_handle%2Cidentity%2Cmode%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Csigned
+
+The `return_to` arg should NOT be `signed`, it should be the originating URL where you initially logged in.
+
+>> Yes, exactly. That's also my understanding of the spec.
+
+> I think you're confusing 'openid.return_to' with 'return_to'. The
+> former is present above, and is, indeed, the originating url, the latter
+> is part of the *value* of the 'openid.signed' parameter generated by myopenid.com. --[[Joey]]
+
+Also, I dunno what the assoc_handle is doing spitting out an arg like `{HMAC-SHA1}{49cdce76}{BhuXXw%3D%3D}` it should be processed further. I have the needed perl packages installed (latest for Lenny). Hrm, would endianness matter?
+
+> Again, this value is created by the openid server, not by ikiwiki.
+> I see the same HMAC-SHA1 when using myopenid, and completly different
+> things for other openid servers. (Ie, when using livejournal as an openid server,
+> `openid.assoc_handle=1239305290:STLS.QiU6zTZ6w2bM3ttRkdaa:e68f91b751`)
+
+>> OK, I wasn't too sure about that, seemed bogus or somehow wrong or in error, like it wasn't actually being `completed`.
+
+> I'm fairly sure that is all a red herring.
+>
+> So, when I was talking about reproducing the bug, I was thinking perhaps you could tell me what openid server you're using,
+> etc, so I can actually see the bug with my own eyes.
+
+>> myopenid.com, with the CNAME option turned on.
+
+> The sanitised url parameters you've provided are not generated by ikiwiki at all.
+> They don't even seem to be generated by the underlying [[!cpan Net::OpenID]] library.
+
+>> That was a server log entry with date/host/time stripped, and my URL also stripped. Everything else is as was in the log. I installed the Debian packages in Lenny, both server and consumer OpenID Perl packages.
+
+> I'm pretty sure that what you're showing me is the url myopenid redirects
+> the browser to after successfully signing in. At that point, ikiwiki
+> should complete the signin. What fails at this point? How can I reproduce this failure? --[[Joey]]
+
+I'll try it again myself. I had tried it oh probably 6 times before I finally gave up on it. Maybe I'm getting rusty and I'm just PEBKACing all over the place. :P
+
+Also, to address the point about this discussion being in the wrong area (not under bugs), should I move it, or will you? I don't mind doing it, if you can't.
-The easiest way to install ikiwiki is using the Debian package, but you can
-also [[download]] the source and install it by hand. Ikiwiki should work on
-most unix-like systems.
+This page documents how to install ikiwiki if a prepackaged version is not
+available for your distribution, and you are faced with [[downloading|download]]
+the source and installing by hand. Ikiwiki should work on most unix-like
+systems.
## Dependencies
It's recommended you have a C compiler, as ikiwiki uses one to build
wrappers.
-Ikiwiki requires the [[cpan Text::Markdown]], [[cpan URI]],
-[[cpan HTML::Parser]], [[cpan HTML::Template]], and [[cpan HTML::Scrubber]]
+Ikiwiki requires the [[!cpan Text::Markdown]], [[!cpan URI]],
+[[!cpan HTML::Parser]], [[!cpan HTML::Template]], and [[!cpan HTML::Scrubber]]
perl modules be installed. It can also use a lot of other perl modules, if
they are available.
Various [[plugins]] use other perl modules and utilities; see their individual
documentation for details.
-## Debian
-
-The Debian packages depend on and recommend an appropriate set of packages,
-so just install ikiwiki using apt.
-
-## Fedora 7
-
-While Fedora 7 doesn't have an ikiwiki package, you can install needed
-perl modules using this command:
-
- yum install perl-Text-Markdown perl-Mail-Sendmail perl-HTML-Scrubber \
- perl-XML-Simple perl-TimeDate perl-HTML-Template perl-CGI-FormBuilder \
- perl-CGI-Session perl-File-MimeInfo perl-gettext perl-Authen-Passphrase
-
-## Installing by hand
+### Installing dependencies by hand
If you want to install by hand from the tarball, you should make sure that
all the perl modules are installed. This is one way to install them, using
PERL5LIB=`pwd` PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'CPAN::Shell->install("Bundle::IkiWiki")'
PERL5LIB=`pwd` PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'CPAN::Shell->install("Bundle::IkiWiki::Extras")'
+## Installing ikiwiki by hand
+
Then to build and install ikiwiki:
perl Makefile.PL # PREFIX=/dir to install elsewhere
+No matter what I do, ikiwiki gives me a `Can't locate loadable object for module Locale::gettext in @INC` although I've installed (and reinstalled) the Locale module, and no luck. If I look at the directories in the INC path, I can see the file. The wiki won't compile in spite of this, and I've tried everything I can think of.. -- [[tychoish]]
+
+> Sounds like the `Locale::gettext` perl module is there, but your perl
+> installation is broken so that the accompnying so file is not there, or
+> doesn't work. On my system I have
+> `/usr/lib/perl5/Locale/gettext.pm` and
+> `/usr/lib/perl5/auto/Locale/gettext.so` -- suspect your problem is with
+> the second one.
+>
+> If you can't fix it, this problem could probably be worked around by
+> unsetting all environment variables when running ikiwiki (`LANG`,
+> `LC_ALL`, `LC_MESSAGES`). Then it won't try to load `Locale::gettext` at
+> all. --[[Joey]]
+
+---
+
I am trying to install Ikiwiki version 2.1 from the source tarball.
It has all gone fairly smoothly until I try and run 'make'.
## Installation in a non-root enviroment
I had a pretty hellacious time installing Ikiwiki (largely due to problems
-in Perl) and documented them in [[tips/SharedHosting]]. I'd like to get feedback on the doc and also know if I should file a few bugs to make the installation process a little friendlier to non-root folks. Thanks for the great app!
+in Perl) and documented them in [[tips/Dreamhost]]. I'd like to get feedback on the doc and also know if I should file a few bugs to make the installation process a little friendlier to non-root folks. Thanks for the great app!
## Typing error?
usemymalloc=n, bincompat5005=undef
Not sure how to provide proper version information for you.--[[vibrog]]
+
+---
+
+I've tried a couple of times and my cpan has never recognised Bundle::IkiWiki. Is that section of the page still accurate? -- [[users/Jon]]
+
+> Are you running perl with the environemnt settings specified on the page?
+> Can you show how it fails to find the bundle? --[[Joey]]
+
+>> I was not. Next time I build I will have to try that (I'll need to tweak it as I already override PERL5LIB; also I need to specify http proxies). Thanks for your help! -- [[users/Jon]]
+
+---
+
+##Further problems with Bundle::IkiWiki
+I'm also having trouble with finding Bundle::IkiWiki. I've tried it with the environment settings and without them, and also using the interactive
+form of the cpan command. I've also gone to cpan.org and searched -- eg
+
+ http://search.cpan.org/search?query=ikiwiki&mode=all
+
+and no Bundle for IkiWiki comes up at all.
+
+The error I get from the various cpan attempts is basically always the same:
+
+ Warning: Cannot install Bundle::IkiWiki, don't know what it is.
+ Try the command
+
+ i /Bundle::IkiWiki/
+
+ to find objects with matching identifiers.
+
+When I try that command, BTW, it basically seems to find the same stuff I get when searching on the cpan web site.
+
+This happens both on Ubuntu 8.04 and CentOS 5.1
+
+Any help would be greatly appreciated... --kent
+
+> Bundle::IkiWiki is included in ikiwiki itself, so of course cpan.org
+> does not know about it.
+>
+> If you can show me exactly what command you ran (the tested, working
+> commands on the parent page?) and how it failed, I can try to debug
+> your problem.
+
+Just today I noticed the "Bundle" subdirectory. What a moron I am! :-) Also, I misunderstood the PERL5LIB=`pwd` part --
+I glibly thought it indicated the sink for the installation of the modules, rather than the source, and I was running
+the cpan command from another window in a different directory, and just spiraled down into error...
+
+> The real question in my mind is why you'd want to do this at all when
+> using Ubuntu, which incldues packages of ikiwiki and all its
+> dependencies. --[[Joey]]
+
+For ubuntu 8.04:
+
+ $ ikiwiki --version
+ ikiwiki version 2.32.3ubuntu2.1
+ $
+
+I was just trying to get the latest version.
+
+In any case, thanks for the help, and thanks for the superb software. I really like it a lot.
+
+---
+
+## Prerequisite modules not found for non-root user
+Hi, I'm a non-root user trying to use IkiWiki on an academic webserver with Perl 5.8.8 but several missing modules, so I grab them from CPAN (edited):
+
+ cd ~; PERL5LIB=`pwd`/ikiwiki:`pwd`/ikiwiki/cpan:`pwd`/lib/perl5 PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'CPAN::Shell->install("Bundle::IkiWiki")'
+
+That puts a lot of files in ~/.cpan. Then when I go into the directory where I untarred IkiWiki and try to run the Perl makefile:
+
+ cd ~/ikiwiki; perl Makefile.PL PREFIX=$HOME/ikiwiki
+
+I get warnings that all the modules needed were not found:
+
+Warning: prerequisite CGI::FormBuilder not found.
+Warning: prerequisite CGI::Session 0 not found.
+Warning: prerequisite Date::Parse 0 not found.
+Warning: prerequisite HTML::Scrubber 0 not found.
+Warning: prerequisite HTML::Template 0 not found.
+Warning: prerequisite Mail::Sendmail 0 not found.
+Warning: prerequisite Text::Markdown 0 not found.
+
+CORRECTION 1: I played around with CPAN and got the installation to the point of succeeding with >99% of tests in "make test".
+
+> What was the magic CPAN rune that worked for you? --[[Joey]]
+
+An attempt of "make install" failed while trying to put files in /etc/IkiWiki but per the output's instructions, I reran "make install" and that seemed to work, until this error, which doesn't seem to be satisfiable:
+
+ Warning: You do not have permissions to install into /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi at /usr/lib/perl5/5.8.8/ExtUtils/Install.pm line 114.
+ Installing /usr/lib/perl5/site_perl/5.8.8/IkiWiki.pm
+ mkdir /usr/lib/perl5/site_perl/5.8.8/IkiWiki: Permission denied at /usr/lib/perl5/5.8.8/ExtUtils/Install.pm line 176
+
+Any suggestions? Whew!
+
+> When you build ikiwiki, try doing it like this to make it
+> install to your home directory. Then you can run `~/bin/ikiwiki`
+> --[[Joey]]
+
+ perl Makefile.PL INSTALL_BASE=$HOME PREFIX=
+ make
+ make install
posted. [[IkiWikiUsers]] are recommended to subscribe to this page's RSS
feed.
-[[inline pages="news/* and !*/Discussion"
+[[!inline pages="news/* and !news/*/* and !news/discussion"
feedpages="created_after(news/Article_on_Ikiwiki_as_a_BTS)" rootpage="news" show="30"]]
By the way, some other pages with RSS feeds about ikiwiki include
--- /dev/null
+I've produced a [code_swarm](http://vis.cs.ucdavis.edu/~ogawa/codeswarm/)
+visualization of the first 2+ years of ikiwiki's commit history.
+
+[[!img screenshot.png size="480x360" alt="screenshot"]]
+
+* [15 mb avi](http://kitenet.net/~joey/screencasts/ikiwiki_swarm.avi)
+* [stream on vimeo](http://vimeo.com/1324348)
+
+PS, while I'm posting links to videos, here's a
+[video of a lightning talk about ikiwiki](http://log.hugoschotman.com/hugo/2008/07/webtuesday-2008-07-08-lightning-talk-by-axel-beckert-about-ikiwiki.html).
+
+--[[Joey]]
+
+### notes
+
+Interesting things to watch for:
+
+* Initial development of ikiwiki to the point it was getting web edits.
+ (First 2 seconds of video!)
+* Introduction to plugin support, and later, plugin changes dominating code
+ changes.
+* Introduction of openid support and the resulting *swarm* of openid
+ commenters.
+* Switch to git, my name in the logs changes from "joey" to "Joey Hess",
+ and there are more code commits directly from others.
+
+Getting the commit log was tricky because every web commit is in there too,
+so it has to deal with things like IPs and openids. The [[code_swarm_log.pl]]
+script will munge the log to handle these, and it was configured with
+[[code_swarm.config]].
+
+Video editing by kino, ffmpeg, ffmpeg2theora, and too many hours of pain.
+
+Audio by the Punch Brothers.
--- /dev/null
+# This is a sample configuration file for code_swarm for ikiwiki
+
+# Frame width
+Width=640
+
+# Frame height
+Height=480
+
+# Input file
+InputFile=data/sample-repevents.xml
+
+# Particle sprite file
+ParticleSpriteFile=particle.png
+
+# Project time per frame
+MillisecondsPerFrame=21600000
+#MillisecondsPerFrame=43200000
+
+# Background in R,G,B
+Background=0,0,0
+
+# Color assignment rules
+# Keep in order, do not skip numbers. Numbers start
+# at 1.
+#
+# Pattern: "Label", "regex", R,G,B R,G,B
+# Label is optional. If it is omitted, the regex
+# will be used.
+#
+
+ColorAssign1="Discussion (blue)",".*discussion.*", 0,0,255, 0,0,255
+ColorAssign2="Docs (green)",".*\.mdwn", 255,0,0, 255,0,0
+ColorAssign3="Plugins (orange)",".*Plugin/.*", 255,116,0, 255,116,0
+ColorAssign4="Code (red)",".*\.p[ml]", 0,255,0, 0,255,0
+
+# Save each frame to an image?
+TakeSnapshots=true
+
+# Where to save each frame
+SnapshotLocation=frames/code_swarm-#####.png
+
+# Create a glow around names? (Runs slower)
+NameHalos=false
+
+# Natural distance of files to people
+EdgeLength=40
+
+debug=false
+
+# OpenGL is experimental. Use at your own risk.
+UseOpenGL=false
--- /dev/null
+#!/usr/bin/perl
+# Munge a git log into log for code_swarm.
+# Deals with oddities of ikiwiki commits, like web commits, and openids.
+use IkiWiki;
+use IkiWiki::Plugin::openid;
+
+my $sep='-' x 72;
+$/=$sep."\n";
+
+my %config=IkiWiki::defaultconfig();
+
+foreach (`git-log --name-status --pretty=format:'%n$sep%nr%h | %an | %ai (%aD) | x lines%n%nsubject: %s%n'`) {
+ my ($subject)=m/subject: (.*)\n/m;
+ if ($subject=~m/$config{web_commit_regexp}/) {
+ my $user = defined $2 ? "$2" : "$3";
+ my $oiduser = IkiWiki::openiduser($user);
+ if (defined $oiduser) {
+ $oiduser=~s/ \[.*\]//; # too much clutter for code_swarm
+ $user=$oiduser;
+ }
+ s/ \| [^|]+ \| / | $user | /;
+ }
+ s/subject: (.*)\n\n//m;
+ print;
+}
+## Ikiwiki 3.12
+
+Joey, what about news for Ikiwiki 3.12? The changelog says is has been released
+6 days ago... :) --[[Paweł|ptecza]]
+
+---
+
+## Ikiwiki 2.14
+
Hi Joey! Where can I find the source package for ikiwiki 2.14? I rather prefer
`wget` than `git` to download it :) I've just checked
[Debian page of ikiwiki source package](http://packages.debian.org/unstable/source/ikiwiki)
--- /dev/null
+Now you can use [[git]] to clone this wiki, and push your changes back,
+thanks to ikiwiki's new support for [[tips/untrusted_git_push]]. Enjoy
+working on the wiki while offline! --[[Joey]]
--- /dev/null
+Thanks, Joey! This is awesome...I had to try it out :)
+--[[JasonBlevins]]
+
+I am really happy to hear of this new feature, that I was (more or less)
+secretly dreaming of. But - and that's why I'm still insanely editing
+this wiki inside a web browser - I wonder how I'll use it for real: my
+own master branch contains a few dozens merge commits, and one is created
+every time I `git pull` ikiwiki repository (or another clone of it, living
+on one of my other boxes that by chance had Internet access more recently).
+I do not want to clutter Joey's repository with these commits, so I guess
+I have to learn some more of Git everything-is-possible world (a nice thing
+is: I am not limited anymore to "Emacs can do it", and I'm now in a position
+to say "Git can do it" or "ikiwiki already does it", depending on the
+situation). Well, let's focus. Git wizards amongst us (let's use this wiki
+as if it were users@ikiwiki.info, ok?), what would you suggest? I was thinking
+of having a new branch in my cloned repository, dedicated to editing this wiki;
+I could use `rebase` instead of `fetch+merge` to get the new upstream commits
+into this special-purpose branch. I guess it would work nicely if I had only
+one offline box with not-yet-pushed changes at the same time, but would break
+in awful and various ways when it is not the case. Any alternative idea?
+--[[intrigeri]]
+
+> Not that I'm very careful to avoid pushing merge commits (see git log ;-),
+> but I sometimes use `git pull --rebase` to pull changes from a repo. That
+> will rebase your local changes on top of the changes pulled, avoiding the
+> merge commits. I'm sure more involved solutions are possible. --[[Joey]]
+
+> I decided to use my local `master` branch as a copy of `origin/master`
+> (kitenet) and move my local modifications to a separate branch. I'm using
+> `master` to edit the wiki but there is still the problem of new upstream
+> commits since the last pull. I already had this problem as Joey had pushed
+> some changes while I was editing locally. Not knowing about
+> `pull --rebase`, I took the long way out: branch, roll back HEAD, rebase,
+> and merge. That was too much work...It looks like `pull --rebase` is the
+> way to go. --[[JasonBlevins]]
+
+Awesome ! --[[xma]]
the procedure described at [[tips/switching_to_usedirs]]
or edit your setup file to turn `usedirs` off: `usedirs => 0,`
* [[plugins/OpenID]] logins are now enabled by default, if the
- [[cpan Net::OpenID::Consumer]] perl module is available. Password logins
+ [[!cpan Net::OpenID::Consumer]] perl module is available. Password logins
are also still enabled by default. If you like, you can turn either OpenID
or password logins off via the `disable_plugins` setting.
* Some support for other markup languages than markdown: rst, textile.
* Unit test suite, with more than 300 tests.
-[[meta date="2007-04-30 00:51:57 -0400"]]
+[[!meta date="2007-04-30 00:51:57 -0400"]]
--- /dev/null
+Ikiwiki has reached version 3.0 and entered a new phase in its
+[[development_cycle|roadmap]].
+
+The 3.0 release of ikiwiki changes several defaults and finishes
+some transitions. You will need to modify your wikis to work with
+ikiwiki 3.0. A document explaining the process is available
+in [[tips/upgrade_to_3.0]].
+
+The highlights of the changes in version 3.0 include:
+
+* Support for uploading [[attachments|plugins/attachment]].
+* Can [[plugins/rename]] and [[plugins/remove]] pages and files via the web.
+* [[Web_based_setup|plugins/websetup]].
+* Blog-style [[plugins/comments]] as an alternative to Discussion pages.
+* Many other new plugins including [[plugins/htmlbalance]], [[plugins/format]],
+ [[plugins/progress]], [[plugins/color]], [[plugins/autoindex]],
+ [[plugins/cutpaste]], [[plugins/hnb]], [[plugins/creole]], [[plugins/txt]],
+ [[plugins/amazon_s3]], [[plugins/pinger]], [[plugins/pingee]],
+ [[plugins/edittemplate]]
+* The RecentChanges page is compiled statically, not generated from the CGI.
+* Support for additional revision control systems: [[rcs/bzr]],
+ [[rcs/monotone]]
+* Support for [[tips/untrusted_git_push]].
+* A new version (3.00) of the plugin API, exporting additional
+ commonly used functions from `IkiWiki.pm`.
+* Nearly everything in ikiwiki is now a plugin, from WikiLinks to
+ page editing, to RecentChanges.
+* Far too many bug fixes, features, and enhancements to list here.
+
+Thanks to the many contributors to ikiwiki 3.0, including:
+
+ Jelmer Vernooij, Recai Oktaş, William Uther, Simon McVittie, Axel Beckert,
+ Bernd Zeimetz, Gabriel McManus, Paweł Tęcza, Peter Simons, Manoj
+ Srivastava, Patrick Winnertz, Jeremie Koenig, Josh Triplett, thm, Michael
+ Gold, Jason Blevins, Alexandre Dupas, Henrik Brix Andersen, Thomas Keller,
+ Enrico Zini, intrigeri, Scott Bronson, Brian May, Adeodato Simó, Brian
+ Downing, Nis Martensen. (And anyone I missed.)
+
+Also, thanks to the users, bug submitters, and documentation wiki editors.
+Without you, ikiwiki would just be a little thing I use for my home page.
+
+--[[Joey]]
OpenID, and see how OpenID works for you. And let me know your feelings about
making such a switch. --[[Joey]]
-[[poll 59 "Accept only OpenID for logins" 18 "Accept only password logins" 35 "Accept both"]]
+[[!poll 63 "Accept only OpenID for logins" 20 "Accept only password logins" 36 "Accept both"]]
> can configure it to eg, subscribe your email address to changes to pages.
> --[[Joey]]
+OK, my openid login works too. One question though, is there a setup parameter which controls whether new registrations are permitted at all? For instance, I'm thinking that I'd like to use the wiki format for content, but I don't want it editable by anyone who isn't already set up. Does this work? --[[Tim Lavoie]]
+
----
# How to ban an IP address?
> Error: /srv/web/ikiwiki.info/todo/Configurable_minimum_length_of_log_message_for_web_edits/index.html independently created, not overwriting with version from todo/Configurable_minimum_length_of_log_message_for_web_edits
-[[jondowland]]
+[[users/jon]]
----
### Logging Out
-If I've logged in by OpenID, how do I log out? I don't see any logout button anywhere on IkiWIki. (is it because I hit "forever" for my OpenID authorization duration?)
+If I've logged in by OpenID, how do I log out? I don't see any logout
+button anywhere on IkiWiki. (is it because I hit "forever" for my OpenID authorization duration?)
> No, it's because it's on the preferences page! That's somewhat non-obvious...
>> This is a problem with having a static wiki. If I just put "Logout" as
> don't check the box that makes your provider set a cookie when you log in.)
>
> AFAIK openid doesn't have single signoff capabilities yet. --[[Joey]]
+
+I'm having a problem using my preferred openid. I have
+http://thewordnerd.info configured as a delegate to
+thewordnerd.myopenid.com. It works fine on Lighthouse, Slicehost and
+everywhere else I've used it. Here, though, if I use the delegate I'm sent
+to my openid identity URL on myopenid.com. If I use the identity URL
+directly, I get the verification page.
+
+Is my delegation broken in some way that works for all these other apps but
+which fails here? Or is something broken in Ikiwiki's implementation?
+
+> I guess this is the same issue filed by you at
+> [[bugs/OpenID_delegation_fails_on_my_server]] --[[Joey]]
+
+Yes. I'd only recently set up my server as a delegate under wordpress, so still thought that perhaps the issue was on my end. But I'd since used my delegate successfully elsewhere, so I filed it as a bug against ikiwiki.
Quick poll: Do you feel that ikiwiki is fast enough on this server, or
should I move it to my much beefier auxiliary server?
-[[poll open=no 40 "It's fast enough" 6 "It's too slow!" 4 "No opinion"]]
+[[!poll open=no 40 "It's fast enough" 6 "It's too slow!" 4 "No opinion"]]
If you have specifics on performance issues, you might mention them on the
[[discussion]] page.
+++ /dev/null
-**This release fixes an important security hole, upgrade immediately.**
-
-News for ikiwiki 2.48:
-
- If you allowed password based logins to your wiki, those passwords were
- stored in cleartext in the userdb. To guard against exposing users'
- passwords, I recommend you install the [[cpan Authen::Passphrase]] perl module, and
- then run `ikiwiki-transition hashpassword /path/to/srcdir` to replace all
- existing cleartext passwords with strong (blowfish) hashes.
-
-ikiwiki 2.48 released with [[toggle text="these changes"]]
-[[toggleable text="""
- * Fix security hole that occurred if openid and passwordauth were both
- enabled. passwordauth would allow logging in as a known openid, with an
- empty password. Closes: #[483770](http://bugs.debian.org/483770)
- (CVE-2008-0169)
- * Add rel=nofollow to edit links. This may prevent some spiders from
- pounding on the cgi following edit links.
- * passwordauth: If Authen::Passphrase is installed, use it to store
- password hashes, crypted with Eksblowfish.
- * `ikiwiki-transiition hashpassword /path/to/srcdir` can be used to
- hash existing plaintext passwords.
- * Passwords will no longer be mailed, but instead a password reset link.
- * The password\_cost config setting is provided as a "more security" knob.
- * teximg: Fix logurl.
- * teximg: If the log isn't written, avoid ugly error messages.
- * Updated French translation. Closes: #[478530](http://bugs.debian.org/478530)"""]]
+++ /dev/null
-News for ikiwiki 2.49:
-
- The search plugin no longer uses hyperestraier. Instead, to use it you
- will now need to install xapian-omega, and the [[cpan Search::Xapian]],
- [[cpan HTML::Scrubber]], and [[cpan Digest::SHA1]] perl modules. Ie,
- `apt-get install xapian-omega libsearch-xapian-perl libhtml-scrubber-perl libdigest-sha1-perl`
-
- Also, wikis that use the search plugin will need to be rebuilt,
- since the search form has changed. This will not be done automatically,
- but can be done by running `ikiwiki-mass-upgrade` as root, or
- running `ikiwiki -setup` on individual setup files.
-
-ikiwiki 2.49 released with [[toggle text="these changes"]]
-[[toggleable text="""
- * haiku: Generate valid xhtml.
- * ikiwiki-mass-rebuild: Don't trust $! when setting $)
- * inline: The optimisation in 2.41 broke nested inlines. Detect those
- and avoid overoptimising.
- * search: Converted to use xapian-omega.
- * Filter hooks are no longer called during the scan phase. This will
- prevent wikilinks added by filters from being scanned properly. But
- no known filter hook does that, so let's not waste time on it.
- * Pass a destpage parameter to the sanitize hook.
- * The search interface now allows searching for a page by title
- ("title:foo"), as well as for pages that contain a given link
- ("link:bar")."""]]
+++ /dev/null
-ikiwiki 2.50 released with [[toggle text="these changes"]]
-[[toggleable text="""
- * img: Support captions.
- * img: Don't generate empty title attributes, etc.
- * img: Allow setting defaults for class and id too.
- * ikiwiki-mass-rebuild: Make group list comparison more robust.
- * search: Work around xapian bug #486138 by only stemming locales
- in a whitelist."""]]
\ No newline at end of file
+++ /dev/null
-ikiwiki 2.51 released with [[toggle text="these changes"]]
-[[toggleable text="""
- * Improve toplevel parentlink to link directly to index.html when usedirs is
- disabled.
- * map: Add a "show" parameter. "show=title" can be used to display page
- titles, rather than the default page name. Based on a patch from
- Jaldhar H. Vyas, Closes: #[484510](http://bugs.debian.org/484510)
- * hnb: New plugin, contributed by Axel Beckert.
- * meta: Store "description" in pagestate for use by other plugins.
- * map: Support show=description.
- * textile: The Text::Textile perl module has some regexps that fail if
- input is flagged as utf-8, but contains invalid characters such as 0x92.
- To prevent it from crashing, re-encode the content before calling it,
- which will ensure that it's really utf-8.
- * Version the suggests of xapian-omega to a version known to be new enough
- to work with ikiwiki. Reportedly, version 0.9.9 is too old to work.
- Closes: #[486592](http://bugs.debian.org/486592)
- * creole: New plugin from Bernd Zeimetz. Closes: #[486930](http://bugs.debian.org/486930)
- * aggregate: Add template parameter.
- * Add support for the universal edit button <http://universaleditbutton.org/>
- (To get this on all pages of an exiting wiki, rebuild the wiki.)
- * txt: New plugin, contributed by Gabriel McManus.
- * smiley: Generate links relative to the destpage. (Fixes a reversion from
- 2.41.)
- * toc: Revert change in 2.45 that made it run at sanitize time. That broke
- use of toc in a sidebar.
- * Call format hooks when generating page previews, thus fixing toc display
- there, as well as fixing inlins to again display in page previews, since
- it's started using format hooks. This also allows several other things,
- like embed, that use format hooks, to work during page preview time.
- * Format hooks should not rely on getting an entire html document, as they
- will only get the body during page preview.
- * toggle: Deal with preview mode when adding javascript."""]]
\ No newline at end of file
+++ /dev/null
-News for ikiwiki 2.52:
-
- All wikis need to be rebuilt on upgrade to this version. If you listed your
- wiki in /etc/ikiwiki/wikilist this will be done automatically when the
- Debian package is upgraded. Or use ikiwiki-mass-rebuild to force a rebuild.
-
-ikiwiki 2.52 released with [[toggle text="these changes"]]
-[[toggleable text="""
- * attachment: New plugin for uploading and managing attachments.
- This includes a fairly powerful PageSpec based admin pref for deciding
- whether to accept a given upload, and an attachment management interface
- on the edit page.
- (Sponsored by The TOVA Company.)
- * If attachments are not enabled, configure CGI.pm to disable file
- uploads by default. (An anti-DOS measure.)
- * toggle: Add support for toggles that are open by default.
- * toggle: Fix to work in preview mode.
- * toggle: Add javascript to top of page, not to end. This avoids flicker
- since closed toggles will not be displayed as the page is loading.
- * The editpage form now uses the raw page name, not the page title, in its
- 'page' cgi parameter. Using the title was ambiguous and made it
- impossible to tell between some pages, like "foo/bar" and "foo\_\_47\_\_bar",
- sometimes causing the wrong page to be edited.
- * This change means that some edit links need to be updated.
- Force a rebuild on upgrade to this version.
- * Above change also allowed really fixing escaped slashes from the blogpost
- form."""]]
\ No newline at end of file
--- /dev/null
+ikiwiki 3.141 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * comment: Make comment directives no longer use the internal "\_comment"
+ form, and document the comment directive syntax.
+ * Avoid relying on translators preserving the case when translating
+ "discussion", which caused Discussion pages to get unwanted Discussion
+ links.
+ * Tighten up matching of bare words inside directives; do not
+ allow an unterminated triple string to be treated as a series
+ of bare words. Fixes runaway regexp recursion/backtracking
+ in strange situations.
+ * Setup automator: Check that each plugin added to the generated
+ setup file can be loaded and that its config is ok. If a plugin
+ fails for any reason, disable it in the generated file.
+ Closes: [532001](http://bugs.debian.org/532001)
+ * pagecount: Fix broken optimisation for * pagespec.
+ * goto: Support being passed a page title that is not a valid page
+ name, to support several cases including mercurial's long user
+ names on the RecentChanges page, and urls with spaces being handled
+ by the 404 plugin.
+ * Optimise use of gettext, and avoid ugly warnings if Locale::gettext
+ is not available. Closes: #[532285](http://bugs.debian.org/532285)
+ * meta: Add openid delegate parameter to allow delegating only
+ openid or openid2.
+ * Disable the Preferences link if no plugin with an auth hook is enabled.
+ * Updated French translation. Closes: #[532654](http://bugs.debian.org/532654)
+ * aggregate: Fix storing of changed md5.
+ * aggregate: Avoid resetting ctime when an item md5 changes."""]]
--- /dev/null
+Version 3.141!? Is it not a mistake? Maybe you meant 3.14.1 or 3.15?
+--[[Paweł|users/ptecza]]
+
+> I suspect the next version will be 3.1415 ;) -- [[Jon]]
+
+>> And next 3.14159, 3.141592, etc. :) I think that version schema
+>> should be patented by Joey ;) --[[Paweł|users/ptecza]]
+
+>>> That's not exactly new; quoting from <http://www-cs-faculty.stanford.edu/~knuth/abcde.html>:
+>>>
+>>>> The latest and best TeX is currently version 3.1415926 (and plain.tex is version 3.141592653); METAFONT is currently version 2.718281 (and plain.mf is version 2.71). My last will and testament for TeX and METAFONT is that their version numbers ultimately become $\pi$ and $e$, respectively. At that point they will be completely error-free by definition.
+>>>
+>>> --[[tschwinge]]
+
+>>>> Thanks for the info, Thomas! I didn't know about it. Sorry Joey,
+>>>> but Don Knuth was faster. What a pity... ;) --[[Paweł|users/ptecza]]
--- /dev/null
+ikiwiki 3.1415 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * img: Fix extra double quote with alt text. (smcv)
+ * Updated French debconf templates translation. Closes: #[535103](http://bugs.debian.org/535103)
+ * openid: Support Net::OpenID 2.x when pretty-printing
+ openids. (smcv)
+ * highlight: Fix utf-8 encoding bug. Closes: #[535028](http://bugs.debian.org/535028)"""]]
\ No newline at end of file
--- /dev/null
+ikiwiki 3.14159 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * svn: Fix rcs\_rename to properly scope call to dirname.
+ * img: Pass the align parameter through to the generated img tag.
+ * Move OpenID pretty-printing from openid plugin to core (smcv)"""]]
\ No newline at end of file
--- /dev/null
+ikiwiki 3.141592 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * Add new hooks: canremove, canrename, rename. (intrigeri)
+ * rename: Refactor subpage rename handling code into rename hook. (intrigeri)
+ * po: New plugin, suporting translation of wiki pages using po files.
+ (intrigeri)
+ * Add build machinery to build po files to translate the underlay wikis,
+ * Add further build machinery to generate translated underlays from
+ the po file, for use by wikis whose primary language is not English.
+ * Add Danish basewiki translation by Jonas Smedegaard.
+ * img: Fix adding of dependency from page to the image.
+ * pagestats: add `among` parameter, which only counts links from specified
+ pages (smcv)
+ * pagestats: when making a tag cloud, don't emit links where the tag is
+ unused (smcv)
+ * map: Avoid emitting an unclosed ul element if the map is empty. (harishcm)
+ * inline: Add pagenames parameter that can be used to list a set of
+ pages to inline, in a specific order, without using a PageSpec. (smcv)
+ * Add getsource plugin (Will, smcv)"""]]
\ No newline at end of file
+++ /dev/null
-The administrator of a wiki can choose to lock some pages, which allows
-only the admin to edit them using the online interface. This doesn't
-prevent anyone who can commit to the underlying revision control system
-from editing the pages, however.
-
-To lock a page, log into the wiki as whatever user is configured as the
-admin, and in your Preferences page, you'll find a field listing locked
-pages. This is a [[ikiwiki/PageSpec]], so you have a fair bit of control
-over what kinds of pages to lock. For example, you could choose to lock all
-pages created before 2006, or all pages that are linked to from the page
-named "locked". More usually though, you'll just list some names of pages
-to lock.
-
-One handy thing to do if you're using ikiwiki for your blog is to lock
-"* and !*/Discussion". This prevents others from adding to or modifying
-posts in your blog, while still letting them comment via the Discussion
-pages.
ikiwiki supports adding "History" links to the top of pages to browse the
-revison history of a page. This is enabled by the `historyurl` setting,
+revision history of a page. This is enabled by the `historyurl` setting,
which is used to specify the URL to a web interface such as [[ViewVC]]
(for Subversion) or [[Gitweb]]. In that url, "\[[file]]" is replaced with
the name of the file to view.
+
+The [[plugins/repolist]] plugin can supplement this information with
+urls to the underlying repository of the wiki.
If your patch is non-trivial and might need several iterations to get
right, please consider publishing a [[git]] branch.
-[[inline pages="(todo/* or bugs/*) and link(patch) and !link(bugs/done) and
+[[!inline pages="(todo/* or bugs/*) and link(patch) and !link(bugs/done) and
!link(todo/done) and !*/Discussion" rootpage="todo" archive="yes"]]
--- /dev/null
+Some [[patches|patch]] affect the ikiwiki core, rather than just a plugin.
+This tag collects those patches. Please tag such patches with 'patch/core'
+as well as 'patch'.
+
+[[!inline pages="(todo/* or bugs/*) and link(patch/core)
+ and !link(bugs/done) and !link(todo/done) and !*/Discussion"
+ rootpage="todo" archive="yes"]]
Most of ikiwiki's [[features]] are implemented as plugins. Many of these
plugins are included with ikiwiki.
-[[pagestats pages="plugins/type/* and !plugins/type/slow"]]
+[[!pagestats pages="plugins/type/* and !plugins/type/slow"]]
There's documentation if you want to [[write]] your own plugins, or you can
[[install]] plugins [[contributed|contrib]] by others.
To enable a plugin, use the `--plugin` switch described in
-[[usage]], or the equivalent `add_plugins` line in [[ikiwiki.setup]].
+[[usage]], or the equivalent `add_plugins` line in ikiwiki.setup.
Enable the [[goodstuff]] plugin to get a nice selection of plugins that
will fit most uses of ikiwiki.
## Plugin directory
-[[inline pages="plugins/* and !plugins/type/* and !plugins/write and
+[[!inline pages="plugins/* and !plugins/type/* and !plugins/write and
!plugins/write/* and !plugins/contrib and !plugins/install and !*/Discussion"
-feedpages="created_after(plugins/graphviz)" archive="yes"
+feedpages="created_after(plugins/graphviz)" archive="yes" sort=title
rootpage="plugins/contrib" postformtext="Add a new plugin named:" show=0]]
--- /dev/null
+[[!template id=plugin name=404 author="[[Simon_McVittie|smcv]]"]]
+[[!tag type/useful]]
+
+This plugin lets you use the IkiWiki CGI script as an Apache 404 handler,
+to give the behaviour of various other wiki engines where visiting a
+nonexistent page provides you with a link to create it.
+
+To achieve this, put something like this in the wiki's Apache configuration
+file:
+
+ ErrorDocument 404 /ikiwiki.cgi
+
+(The path here needs to be whatever the path is to the ikiwiki.cgi from
+the root of your web server.)
+
+Or put something like this in the wiki's Lighttpd (>=1.4.17) configuration file:
+
+ server.error-handler-404 = "/ikiwiki.cgi"
+
+
-[[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
+This plugin allows content from other feeds to be aggregated into the
+wiki. To specify feeds to aggregate, use the
+[[ikiwiki/directive/aggregate]] [[ikiwiki/directive]].
- \[[aggregate name="example blog"
- feedurl="http://example.com/index.rss"
- url="http://example.com/" updateinterval="15"]]
-
-That example aggregates posts from the specified RSS feed, updating no
-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.
-
-## 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
-[[htmltidy]] plugin is suggested, since feeds can easily contain html
-problems, some of which tidy can fix.
+The [[meta]] and [[tag]] plugins are also recommended. Either the
+[[htmltidy]] or [[htmlbalance]] plugin is suggested, since feeds can easily
+contain html problems, some of which these plugins can fix.
You will need to run ikiwiki periodically from a cron job, passing it the
--aggregate parameter, to make it check for new posts. Here's an example
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.
-## usage
+## aggregated pages
-Here are descriptions of all the supported parameters to the `aggregate`
-directive:
+This plugin creates a page for each aggregated item.
-* `name` - A name for the feed. Each feed must have a unique name.
- Required.
-* `url` - The url to the web page for the feed that's being aggregated.
- Required.
-* `dir` - The directory in the wiki where pages should be saved. Optional,
- if not specified, the directory is based on the name of the feed.
-* `feedurl` - The url to the feed. Optional, if it's not specified ikiwiki
- will look for feeds on the `url`. RSS and atom feeds are supported.
-* `updateinterval` - How often to check for new posts, in minutes. Default
- is 15 minutes.
-* `expireage` - Expire old items from this feed if they are older than
- a specified number of days. Default is to never expire on age.
-* `expirecount` - Expire old items from this feed if there are more than
- the specified number total. Oldest items will be expired first. Default
- is to never expire on count.
-* `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
- aggregatepost.
+If the `aggregateinternal` option is enabled in the setup file (which is
+the default), 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/*)`.
-Note that even if you are using subversion or another revision control
-system, pages created by aggregation will *not* be checked into revision
-control.
+If `aggregateinternal` is disabled, you will need to enable the [[html]]
+plugin as well as aggregate itself, since feed entries will be stored as
+HTML, and as first-class wiki pages -- each one generates
+a separate HTML page in the output, and they can even be edited. This
+option is provided only for backwards compatability.
--- /dev/null
+I'm trying to set up a [planet of my users' blogs](http://help.schmonz.com/planet/). I've enabled the aggregate, meta, and tag plugins (but not htmltidy, that thing has a gajillion dependencies). `aggregateinternal` is 1. The cron job is running and I've also enabled the webtrigger. My usage is like so:
+
+ \[[!inline pages="internal(planet/*) show=0"]]
+
+ \[[!aggregate
+ name="Amitai's blog"
+ url="http://www.schmonz.com/"
+ dir="planet/schmonz-blog"
+ feedurl="http://www.schmonz.com/atom/"
+ expirecount="2"
+ tag="schmonz"
+ ]]
+
+ \[[!aggregate
+ name="Amitai's photos"
+ url="http://photos.schmonz.com/"
+ dir="planet/schmonz-photos"
+ feedurl="http://photos.schmonz.com/main.php?g2_view=rss.SimpleRender&g2_itemId=7"
+ expirecount="2"
+ tag="schmonz"
+ ]]
+
+
+(and a few more `aggregate` directives like these)
+
+Two things aren't working as I'd expect:
+
+1. `expirecount` doesn't take effect on the first run, but on the second. (This is minor, just a bit confusing at first.)
+2. Where are the article bodies for e.g. David's and Nathan's blogs? The bodies aren't showing up in the `._aggregated` files for those feeds, but the bodies for my own blog do, which explains the planet problem, but I don't understand the underlying aggregation problem. (Those feeds include article bodies, and show up normally in my usual feed reader rss2email.) How can I debug this further? --[[schmonz]]
+
+> I only looked at David's, but its rss feed is not escaping the html
+> inside the rss `description` tags, which is illegal for rss 2.0. These
+> unknown tags then get ignored, including their content, and all that's
+> left is whitespace. Escaping the html to `<` and `>` fixes the
+> problem. You can see the feed validator complain about it here:
+> <http://feedvalidator.org/check.cgi?url=http%3A%2F%2Fwww.davidj.org%2Frss.xml>
+>
+> It's sorta unfortunate that [[!cpan XML::Feed]] doesn't just assume the
+> un-esxaped html is part of the description field. Probably other feed
+> parsers are more lenient. --[[Joey]]
+
+>> Thanks for the quick response (and the `expirecount` fix); I've forwarded it to David so he can fix his feed. Nathan's Atom feed validates -- it's generated by the same CMS as mine -- so I'm still at a loss on that one. --[[schmonz]]
+
+>>> Nathan's feed contains only summary elements, with no content elements.
+>>> This is legal according to the Atom spec, so I've fixed ikiwiki to use
+>>> the summary if no content is available. --[[Joey]]
+
+>>>> After applying your diffs, blowing away my cached aggregated stuff, and running the aggregate cron job by hand, the resulting planet still doesn't have Nathan's summaries... and the two posts from each feed that aren't being expired aren't the two newest ones (not sure what the pattern is there). Have I done something wrong? --[[schmonz]]
+
+>>>>> I think that both issues are now fixed. Thanks for testing.
+>>>>> --[[Joey]]
+
+>>>>>> I can confirm, they're fixed on my end. --[[schmonz]]
+
+New bug: new posts aren't getting displayed (or cached for aggregation). After fixing his feed, David posted a new item today, and the aggregator is convinced there's nothing to do, whether by cronjob or webtrigger. I verified that it wasn't another problem with his feed by adding another of my ikiwiki's feed to the planet, running the aggregator, posting a new item, and running the aggregator again: no new item. --[[schmonz]]
+
+> Even if you start it more frequently, aggregation will only occur every
+> `updateinterval` minutes (default 15), maximum. Does this explain what
+> you're seeing? --[[Joey]]
+
+>> Crap, right, and my test update has since made it into the planet. His post still hasn't. So it must be something with David's feed again? A quick test with XML::Feed looks like it's parsing just fine: --[[schmonz]]
+
+ $ perl
+ use XML::Feed;
+ my $feed = XML::Feed->parse(URI->new('http://www.davidj.org/rss.xml')) or die XML::Feed->errstr;
+ print $feed->title, "\n";
+ for my $entry ($feed->entries) {
+ print $entry->title, ": ", $entry->issued, "\n";
+ }
+ ^D
+ davidj.org
+ Amway Stories - Refrigerator Pictures: 2008-09-19T00:12:27
+ Amway Stories - Coffee: 2008-09-13T10:08:17
+ Google Alphabet Update: 2008-09-11T22:55:37
+ Writing for writing's sake: 2008-09-09T23:39:05
+ Google Chrome: 2008-09-02T23:12:26
+ Mister Casual: 2008-07-25T09:01:17
+ Parental Conversations: 2008-07-24T10:44:44
+ Place Of George Orwell: 2008-06-03T22:11:07
+ The Raw Beauty Of A National Duolian: 2008-05-31T12:41:06
+
+> I had no problem getting the "Refrigerator Pictures" post to aggregate
+> here, though without a copy of the old feed I can't be 100% sure I've
+> reproduced your ikiwiki's state. --[[Joey]]
+
+>> Okay, I blew away the cached entries and aggregator state files and reran the aggregator and all appears well again. If the problem recurs I'll be sure to post here. :-) --[[schmonz]]
+
+>>> On the off chance that you retained a copy of the old state, I'd not
+>>> mind having a copy to investigate. --[[Joey]]
+
+>>>> Didn't think of that, will keep a copy if there's a next time. -- [[schmonz]]
-[[template id=plugin name=amazon_s3 author="[[Joey]]"]]
-[[tag type/special-purpose]]
+[[!template id=plugin name=amazon_s3 author="[[Joey]]"]]
+[[!tag type/special-purpose]]
This plugin allows ikiwiki to publish a wiki in the [Amazon Simple Storage
Service](http://aws.amazon.com/s3) (S3). As pages are rendered, ikiwiki
will upload them to Amazon S3. The entire wiki contents, aside from the
ikiwiki CGI, can then be served directly out of Amazon S3.
-You'll need the [[cpan Net::Amazon::S3]] and [[cpan File::MimeInfo]] perl
+You'll need the [[!cpan Net::Amazon::S3]] and [[!cpan File::MimeInfo]] perl
modules and an Amazon S3 account to use this plugin.
## configuration
-[[template id=plugin name=anonok author="[[Joey]]"]]
-[[tag type/auth]]
+[[!template id=plugin name=anonok author="[[Joey]]"]]
+[[!tag type/auth]]
By default, anonymous users cannot edit the wiki. This plugin allows
anonymous web users, who have not signed in, to edit any page in the wiki
by default.
-The plugin also has a configuration setting, `anonok_pagespec`. This
-[[PageSpec]] can be used to allow anonymous editing of matching pages.
+Please think twice before enabling this plugin. If your wiki is accessible
+to the internet, it *will* be subject to spamming if this plugin is
+enabled. Such spam is not only a pain to deal with, but it bloats the
+revision control history of your wiki.
+
+The plugin has a configuration setting, `anonok_pagespec`. This
+[[ikiwiki/PageSpec]] can be used to allow anonymous editing of matching pages.
+
+If you're using the [[comments]] plugin, you can allow anonymous comments
+to be posted by setting:
+
+ anonok_pagespec => "postcomment(*)"
-[[template id=plugin name=attachment core=0 author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=attachment core=0 author="[[Joey]]"]]
+[[!tag type/web]]
This plugin allows files to be uploaded to the wiki over the web.
contains html as a web page; including running any malicious javascript
embedded in that page.
-If you enable this plugin, be sure to lock that down, by entering an
-[[enhanced_PageSpec|ikiwiki/pagespec/attachment]] in the "Allowed
-Attachments" field of the wiki admin's preferences page.
-
-This plugin will use the [[cpan File::MimeInfo::Magic]] perl module, if
-available, for mimetype checking.
-
-The `virusfree` [[PageSpec|ikiwiki/pagespec/attachment]] requires that
-ikiwiki be configured with a virus scanner program via the `virus_checker`
-option in the setup file. If using `clamav`, with `clamd`, set it to
-"clamdscan -". Or to use clamav without the `clamd` daemon, you
-could set it to "clamscan -".
+If you enable this plugin, be sure to lock it down, via the
+`allowed_attachments` setup file option. This is a special
+[[enhanced_PageSpec|ikiwiki/pagespec/attachment]] using tests provided by
+the [[filecheck]] plugin. That plugin will be automatically enabled when
+this plugin is enabled.
--- /dev/null
+[[!template id=plugin name=autoindex core=0 author="[[Joey]]"]]
+[[!tag type/useful]]
+
+This plugin searches for [[SubPages|ikiwiki/subpage]] with a missing parent
+page, and generates the parent pages. The generated page content is
+controlled by the `autoindex.tmpl` [[template|wikitemplates]], which by
+default, uses a [[map]] to list the SubPages.
--- /dev/null
+Would it be possible to add an option to only generate the index files
+for the html output and not place the markdown files in the wiki source?
+
+The reason being that I have a lot of directories which need to be autoindexed,
+but I would prefer if the index files didn't clutter up my git repository.
+
+even without that feature the plugin is a great help, thanks
--- /dev/null
+[[!template id=plugin name=blogspam author="[[Joey]]"]]
+[[!tag type/auth]]
+
+This plugin adds antispam support to ikiwiki, using the
+[blogspam.net](http://blogspam.net/) API. Both page edits and
+[[comment|comments]] postings can be checked for spam. Page edits that
+appear to contain spam will be rejected; comments that look spammy will be
+stored in a queue for moderation by an admin.
+
+To check for and moderate comments, log in to the wiki as an admin,
+go to your Preferences page, and click the "Comment Moderation" button.
+
+The plugin requires the [[!cpan RPC::XML]] perl module.
+
+You can control how content is tested via the `blogspam_options` setting.
+The list of options is [here](http://blogspam.net/api/testComment.html#options).
+By default, the options are configured in a way that is appropriate for
+wiki content. This includes turning off some of the more problematic tests.
+An interesting option for testing is `fail`, by setting it (e.g.,
+`blogspam_options => 'fail'`), *all* comments will be marked as SPAM, so that
+you can check whether the interaction with blogspam.net works.
+
+The `blogspam_pagespec` setting is a [[ikiwiki/PageSpec]] that can be
+used to configure which pages are checked for spam. The default is to check
+all edits. If you only want to check [[comments]] (not wiki page edits),
+set it to "postcomment(*)".
+
+By default, the blogspam.net server is used to do the spam checking. To
+change this, the `blogspam_server` option can be set to the url for a
+different server implementing the same API. Note that content is sent
+unencrypted over the internet to the server, and the server sees
+the full text of the content.
-[[template id=plugin name=brokenlinks author="[[Joey]]"]]
-[[tag type/link type/meta]]
+[[!template id=plugin name=brokenlinks author="[[Joey]]"]]
+[[!tag type/link type/meta]]
-This plugin generates a list of broken links on pages in the wiki. This is
-a useful way to find pages that still need to be written, or links that
-are written wrong.
-
-The optional parameter "pages" can be a [[ikiwiki/PageSpec]] specifying the
-pages to search for broken links, default is search them all.
+This plugin provides a [[ikiwiki/directive/brokenlinks]] [[ikiwiki/directive]]
+that generates a list of broken links on pages in the wiki.
If this plugin is turned on, here's a list of broken links on this wiki:
-[[brokenlinks pages="* and !recentchanges"]]
+[[!brokenlinks pages="* and !recentchanges"]]
-[[template id=plugin name=calendar author="[[ManojSrivastava]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=calendar author="[[ManojSrivastava]]"]]
+[[!tag type/chrome]]
-This plugin displays a calendar, similar to the typical calendars shown on
+This plugin provides a [[ikiwiki/directive/calendar]] [[ikiwiki/directive]].
+The directive displays a calendar, similar to the typical calendars shown on
some blogs.
-# examples
-
- \[[calendar ]]
-
- \[[calendar type="month" pages="blog/* and !*/Discussion"]]
-
- \[[calendar type="year" year="2005" pages="blog/* and !*/Discussion"]]
-
-This plugin is inspired by the calendar plugin for Blosxom, but
-derives no code from it. This plugin is essentially a fancy front end
-to archives of previous pages, usually used for blogs. It can produce
-a calendar for a given month, or a list of months for a given year.
-
Since ikiwiki is a wiki compiler, to keep the calendar up-to-date,
-wikis that include it need to be preiodically refreshes, typically by cron
+wikis that include it need to be periodically refreshes, typically by cron
at midnight. Example crontab:
0 0 * * * ikiwiki -setup ~/ikiwiki.setup -refresh
-The month format calendar simply links to any page posted on each
-day of the month. The year format calendar links to archive pages, with
-names like `archives/2007` (for all of 2007) and `archives/2007/01`
-(for January, 2007). For this to work, you'll need to create these archive
-pages. They typically use [[inline]] to display or list pages created in
-the given time frame.
-
-## usage
-
-* `type` - Used to specify the type of calendar wanted. Can be one of
- "month" or "year". The default is a month view calendar.
-* `pages` - Specifies the [[ikiwiki/PageSpec]] of pages to link to from the
- month calendar. Defaults to "*".
-* `archivebase` - Configures the base of the archives hierarchy. The
- default is "archives". Note that this default can also be overridden
- for the whole wiki by setting `archivebase` in ikiwiki's setup file.
-* `year` - The year for which the calendar is requested. Defaults to the
- current year.
-* `month` - The numeric month for which the calendar is requested, in the
- range 1..12. Used only for the month view calendar, and defaults to the
- current month.
-* `week_start_day` - A number, in the range 0..6, which represents the day
- of the week that the month calendar starts with. 0 is Sunday, 1 is Monday,
- and so on. Defaults to 0, which is Sunday.
-* `months_per_row` - In the annual calendar, number of months to place in
- each row. Defaults to 3.
-
## CSS
The output is liberally sprinkled with classes, for fine grained CSS
* `month-calendar-head` - The head of the month calendar (ie,"March").
* `month-calendar-day-head` - A column head in the month calendar (ie, a
day-of-week abbreviation).
-* `month-calendar-day-noday`, `month-calendar-day-link`,
+* `month-calendar-day-noday`, `month-calendar-day-link`,
`month-calendar-day-nolink`, `month-calendar-day-future`,
`month-calendar-day-this-day` - The day squares on the month calendar,
for days that are not in the month (before or after the month itself), that
--- /dev/null
+It would be nice if the "month" type calendar could collect all of the
+matching pages on a given date in some inline type way. --[[DavidBremner]]
+
+Is it possible to get the calendar to link to pages based not on their timestamp (as I understand that it does now, or have I misunderstood this?) and instead on for example their location in a directory hierarchy. That way the calendar could be used as a planning / timeline device which I think would be great. --[[Alexander]]
+
+I would like the ability to specify relative previous months. This way I could have a sidebar with the last three months by specifying no month, then 'month="-1"' and 'month="-2"'. Negative numbers for the month would otherwise be invalid, so this shouldn't produce any conflicts with expected behavior. (Right?) -- [[StevenBlack]]
-[[template id=plugin name=camelcase author="[[Joey]]"]]
+[[!template id=plugin name=camelcase author="[[Joey]]"]]
This plugin makes words in CamelCase be treated as a [[ikiwiki/WikiLink]].
That is to say, any two or more words capitalised and mashed together are
If this plugin is enabled, this will be a link: SandBox
-[[tag type/link]]
+[[!tag type/link]]
--- /dev/null
+[[!template id=plugin name=color core=0 author="[[ptecza]]"]]
+[[!tag type/chrome]]
+
+This plugin provides a [[ikiwiki/directive/color]] [[ikiwiki/directive]].
+The directive can be used to color a piece of text on a page.
--- /dev/null
+[[!template id=plugin name=comments author="[[Simon_McVittie|smcv]]"]]
+[[!tag type/useful]]
+
+This plugin adds "blog-style" comments. Unlike the wiki-style freeform
+Discussion pages, these comments are posted by a simple form, cannot later
+be edited, and rss/atom feeds are provided of each page's comments.
+
+When using this plugin, you should also enable [[htmlscrubber]] and either
+[[htmltidy]] or [[htmlbalance]]. Directives are filtered out by default, to
+avoid commenters slowing down the wiki by causing time-consuming
+processing. As long as the recommended plugins are enabled, comment
+authorship should hopefully be unforgeable by CGI users.
+
+The intention is that on a non-wiki site (like a blog) you can lock all
+pages for admin-only access, then allow otherwise unprivileged (or perhaps
+even anonymous) users to comment on posts. See the documentation of the
+[[lockedit]] and [[anonok]] pages for details on locking down a wiki so
+users can only post comments.
+
+Individual comments are stored as internal-use pages named something like
+`page/comment_1`, `page/comment_2`, etc. These pages internally use a
+[[comment_directive|ikiwiki/directive/comment]].
+
+There are some global options for the setup file:
+
+* `comments_pagespec`: [[ikiwiki/PageSpec]] of pages where comments are
+ allowed. The default is not to allow comments on any pages. To allow
+ comments to all posts to a blog, you could use
+ `blog/posts/* and !*/Discussion`.
+* `comments_closed_pagespec`: [[ikiwiki/PageSpec]] of pages where
+ posting of new comments is closed, but any existing comments will still
+ be displayed. Often you will list a set of individual pages here.
+ For example: `blog/controversial or blog/flamewar`
+* `comments_pagename`: if this is e.g. `comment_` (the default), then
+ comment pages will be named something like `page/comment_12`
+* `comments_allowdirectives`: if true (default false), comments may
+ contain IkiWiki [[directives|ikiwiki/directive]]
+* `comments_commit`: if true (default true), comments will be committed to
+ the version control system
+* `comments_allowauthor`: if true (default false), anonymous commenters may
+ specify a name for themselves, and the \[[!meta author]] and
+ \[[!meta authorurl]] directives will not be overridden by the comments
+ plugin
+
+## comment moderation
+
+If you enable the [[blogspam]] plugin, comments that appear spammy will be
+held for moderation. Wiki admins can access the comment moderation queue
+via a button on their Preferences page.
+
+The comments are stored in `.ikiwiki/comments_pending/`, and can be
+deleted, or moved into the wiki's srcdir to be posted.
--- /dev/null
+## Why internal pages? (unresolved)
+
+Comments are saved as internal pages, so they can never be edited through the CGI,
+only by direct committers.
+
+> So, why do it this way, instead of using regular wiki pages in a
+> namespace, such as `$page/comments/*`? Then you could use [[plugins/lockedit]] to
+> limit editing of comments in more powerful ways. --[[Joey]]
+
+>> Er... I suppose so. I'd assumed that these pages ought to only exist as inlines
+>> rather than as individual pages (same reasoning as aggregated posts), though.
+>>
+>> lockedit is actually somewhat insufficient, since `check_canedit()`
+>> doesn't distinguish between creation and editing; I'd have to continue to use
+>> some sort of odd hack to allow creation but not editing.
+>>
+>> I also can't think of any circumstance where you'd want a user other than
+>> admins (~= git committers) and possibly the commenter (who we can't check for
+>> at the moment anyway, I don't think?) to be able to edit comments - I think
+>> user expectations for something that looks like ordinary blog comments are
+>> likely to include "others can't put words into my mouth".
+>>
+>> My other objection to using a namespace is that I'm not particularly happy about
+>> plugins consuming arbitrary pieces of the wiki namespace - /discussion is bad
+>> enough already. Indeed, this very page would accidentally get matched by rules
+>> aiming to control comment-posting... :-) --[[smcv]]
+
+>>> Thinking about it, perhaps one way to address this would be to have the suffix
+>>> (e.g. whether commenting on Sandbox creates sandbox/comment1 or sandbox/c1 or
+>>> what) be configurable by the wiki admin, in the same way that recentchanges has
+>>> recentchangespage => 'recentchanges'? I'd like to see fewer hard-coded page
+>>> names in general, really - it seems odd to me that shortcuts and smileys
+>>> hard-code the name of the page to look at. Perhaps I could add
+>>> discussionpage => 'discussion' too? --[[smcv]]
+
+>>> (I've now implemented this in my branch. --[[smcv]])
+
+>> The best reason to keep the pages internal seems to me to be that you
+>> don't want the overhead of every comment spawning its own wiki page. --[[Joey]]
+
+## Formats (resolved)
+
+The plugin now allows multiple comment formats while still using internal
+pages; each comment is saved as a page containing one `\[[!comment]]` directive,
+which has a superset of the functionality of [[ikiwiki/directives/format]].
+
+## Access control (unresolved?)
+
+By the way, I think that who can post comments should be controllable by
+the existing plugins opendiscussion, anonok, signinedit, and lockedit. Allowing
+posting comments w/o any login, while a nice capability, can lead to
+spam problems. So, use `check_canedit` as at least a first-level check?
+--[[Joey]]
+
+> This plugin already uses `check_canedit`, but that function doesn't have a concept
+> of different actions. The hack I use is that when a user comments on, say, sandbox,
+> I call `check_canedit` for the pseudo-page "sandbox[postcomment]". The
+> special `postcomment(glob)` [[ikiwiki/pagespec]] returns true if the page ends with
+> "[postcomment]" and the part before (e.g. sandbox) matches the glob. So, you can
+> have postcomment(blog/*) or something. (Perhaps instead of taking a glob, postcomment
+> should take a pagespec, so you can have postcomment(link(tags/commentable))?)
+>
+> This is why `anonok_pagespec => 'postcomment(*)'` and `locked_pages => '!postcomment(*)'`
+> are necessary to allow anonymous and logged-in editing (respectively).
+>
+>> I changed that to move the flag out of the page name, and into a variable that the `match_postcomment`
+>> function checks for. Other ugliness still applies. :-) --[[Joey]]
+>
+> This is ugly - one alternative would be to add `check_permission()` that takes a
+> page and a verb (create, edit, rename, remove and maybe comment are the ones I
+> can think of so far), use that, and port the plugins you mentioned to use that
+> API too. This plugin could either call `check_can("$page/comment1", 'create')` or
+> call `check_can($page, 'comment')`.
+>
+> One odd effect of the code structure I've used is that we check for the ability to
+> create the page before we actually know what page name we're going to use - when
+> posting the comment I just increment a number until I reach an unused one - so
+> either the code needs restructuring, or the permission check for 'create' would
+> always be for 'comment1' and never 'comment123'. --[[smcv]]
+
+>> Now resolved, in fact --[[smcv]]
+
+> Another possibility is to just check for permission to edit (e.g.) `sandbox/comment1`.
+> However, this makes the "comments can only be created, not edited" feature completely
+> reliant on the fact that internal pages can't be edited. Perhaps there should be a
+> `editable_pages` pagespec, defaulting to `'*'`? --[[smcv]]
+
+## comments directive vs global setting (resolved?)
+
+When comments have been enabled generally, you still need to mark which pages
+can have comments, by including the `\[[!comments]]` directive in them. By default,
+this directive expands to a "post a comment" link plus an `\[[!inline]]` with
+the comments. [This requirement has now been removed --[[smcv]]]
+
+> I don't like this, because it's hard to explain to someone why they have
+> to insert this into every post to their blog. Seems that the model used
+> for discussion pages could work -- if comments are enabled, automatically
+> add the comment posting form and comments to the end of each page.
+> --[[Joey]]
+
+>> I don't think I'd want comments on *every* page (particularly, not the
+>> front page). Perhaps a pagespec in the setup file, where the default is "*"?
+>> Then control freaks like me could use "link(tags/comments)" and tag pages
+>> as allowing comments.
+>>
+>>> Yes, I think a pagespec is the way to go. --[[Joey]]
+
+>>>> Implemented --[[smcv]]
+
+>>
+>> The model used for discussion pages does require patching the existing
+>> page template, which I was trying to avoid - I'm not convinced that having
+>> every possible feature hard-coded there really scales (and obviously it's
+>> rather annoying while this plugin is on a branch). --[[smcv]]
+
+>>> Using the template would allow customising the html around the comments
+>>> which seems like a good thing? --[[Joey]]
+
+>>>> The \[[!comments]] directive is already template-friendly - it expands to
+>>>> the contents of the template `comments_embed.tmpl`, possibly with the
+>>>> result of an \[[!inline]] appended. I should change `comments_embed.tmpl`
+>>>> so it uses a template variable `INLINE` for the inline result rather than
+>>>> having the perl code concatenate it, which would allow a bit more
+>>>> customization (whether the "post" link was before or after the inline).
+>>>> Even if you want comments in page.tmpl, keeping the separate comments_embed.tmpl
+>>>> and having a `COMMENTS` variable in page.tmpl might be the way forward,
+>>>> since the smaller each templates is, the easier it will be for users
+>>>> to maintain a patched set of templates. (I think so, anyway, based on what happens
+>>>> with dpkg prompts in Debian packages with monolithic vs split
+>>>> conffiles.) --[[smcv]]
+
+>>>>> I've switched my branch to use page.tmpl instead; see what you think? --[[smcv]]
+
+## Raw HTML (resolved?)
+
+Raw HTML was not initially allowed by default (this was configurable).
+
+> I'm not sure that raw html should be a problem, as long as the
+> htmlsanitizer and htmlbalanced plugins are enabled. I can see filtering
+> out directives, as a special case. --[[Joey]]
+
+>> Right, if I sanitize each post individually, with htmlscrubber and either htmltidy
+>> or htmlbalance turned on, then there should be no way the user can forge a comment;
+>> I was initially wary of allowing meta directives, but I think those are OK, as long
+>> as the comment template puts the \[[!meta author]] at the *end*. Disallowing
+>> directives is more a way to avoid commenters causing expensive processing than
+>> anything else, at this point.
+>>
+>> I've rebased the plugin on master, made it sanitize individual posts' content
+>> and removed the option to disallow raw HTML. Sanitizing individual posts before
+>> they've been htmlized required me to preserve whitespace in the htmlbalance
+>> plugin, so I did that. Alternatively, we could htmlize immediately and always
+>> save out raw HTML? --[[smcv]]
+
+>>> There might be some use cases for other directives, such as img, in
+>>> comments.
+>>>
+>>> I don't know if meta is "safe" (ie, guaranteed to be inexpensive and not
+>>> allow users to do annoying things) or if it will continue to be in the
+>>> future. Hard to predict really, all that can be said with certainty is
+>>> all directives will contine to be inexpensive and safe enough that it's
+>>> sensible to allow users to (ab)use them on open wikis.
+>>> --[[Joey]]
+
+----
+
+I have a test ikiwiki setup somewhere to investigate adopting the comments
+plugin. It is setup with no auth enabled and I got hammered with a spam attack
+over the last weekend (predictably). What surprised me was the scale of the
+attack: ikiwiki eventually triggered OOM and brought the box down. When I got
+it back up, I checked out a copy of the underlying git repository, and it
+measured 280M in size after being packed. Of that, about 300K was data prior
+to the spam attack, so the rest was entirely spam text, compressed via git's
+efficient delta compression.
+
+I had two thoughts about possible improvements to the comments plugin in the
+wake of this:
+
+ * comment pagination - there is a hard-to-define upper limit on the number
+ of comments that can be appended to a wiki page whilst the page remains
+ legible. It would be useful if comments could be paginated into sub-pages.
+
+ * crude flood control - asides from spam attacks (and I am aware of
+ [[plugins/blogspam]]), people can crap flood or just aggressively flame
+ repeatedly. An interesting prevention measure might be to not let an IP
+ post more than 3 sequential comments to a page, or to the site, without
+ at least one other comment being interleaved. I say 3 rather than 2 since
+ correction follow-ups are common.
+
+-- [[Jon]]
-[[template id=plugin name=conditional core=1 author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=conditional core=1 author="[[Joey]]"]]
+[[!tag type/format]]
-With this plugin, you can make text be conditionally displayed on a page.
-For example:
-
- \[[if test="enabled(smiley)"
- then="The smiley plugin is enabled :-)"
- else="No smiley plugin here.."]]
-
-If the specified `test` succeeds, the `then` text will be displayed,
-otherwise the `else` text will be displayed. The `else` part is optional.
-
-The `then` and `else` values can include any markup that would be allowed
-in the wiki page outside the template. Triple-quoting the values even allows
-quotes to be included.
-
-The `test` is a [[ikiwiki/PageSpec]]; if it matches any page in the wiki
-then it succeeds. So you can do things like testing for the existence of a
-page or pages, testing to see if any pages were created in a given month,
-and so on.
-
-If you want the [[ikiwiki/PageSpec]] to only match against the page that
-contains the conditional, rather than matching against all pages in the
-wiki, set the "all" parameter to "no".
-
-The regular [[ikiwiki/PageSpec]] syntax is expanded with the following
-additional tests:
-
-* enabled(plugin)
-
- Tests whether the specified plugin is enabled.
-
-* sourcepage(glob)
-
- Tests whether the glob matches the name of the page that contains the
- conditional.
-
-* destpage(glob)
-
- Tests whether the glob matches the name of the page that is being built.
- That might be different than the name of the page that contains the
- conditional, if it's being inlined into another page.
-
-* included()
-
- Tests whether the page is being included onto another page.
+This plugin provides the [[ikiwiki/directive/if]] [[ikiwiki/directive]].
+With this directive, you can make text be conditionally displayed on a page.
> The blank lines in this example are coming from the newline after `then="`, and also from the newline before the close quote. If you remove those newlines, I think it should work. --[[Joey]]
>> No, that's unfortunately not it, see here:
->> [[if test="enabled(trallala)" then="foot"]]
+>> [[!if test="enabled(trallala)" then="foot"]]
>> Continued. But on the other
->> [[if test="enabled(trallala)" then="foot" else="hand:"]]
+>> [[!if test="enabled(trallala)" then="foot" else="hand:"]]
>> Continued. --[[tschwinge]]
>>> Seems ok, no? The only linebreaks I see in the source are the ones you
>>>> Okay, that would explain the linebreak between 1 and 3. But then, why are all linebreaks removed between 3 and 5?
>>>> 1 No, that's unfortunately not it, see here:
->>>> [[if test="enabled(trallala)" then="foot"]]
+>>>> [[!if test="enabled(trallala)" then="foot"]]
>>>> 3 Continued. But on the other
->>>> [[if test="enabled(trallala)" then="foot" else="hand:"]]
+>>>> [[!if test="enabled(trallala)" then="foot" else="hand:"]]
>>>> 5 Continued. --[[tschwinge]]
>>>>> The conditional after 1 evaluates to "", so there's a blank line
<pre>
#### Archives
- \[[calendar type="year" months_per_row="6" pages="blog/* and !*/Discussion"]]
- \[[calendar type="month" pages="blog/* and !*/Discussion"]]
+ \[[!calendar type="year" months_per_row="6" pages="blog/* and !*/Discussion"]]
+ \[[!calendar type="month" pages="blog/* and !*/Discussion"]]
<h4>Indices</h4>
- \[[map pages="archives/* and !*/Discussion"]]
+ \[[!map pages="archives/* and !*/Discussion"]]
</pre>
I am trying to make it so that the archives and index only show up if the destpage is either blog/* or / -- the top of the wiki. Unfortunately, I don't think I am getting the
conditional right -- I have a "]] left over at the end (looking at the rendered html). Ideally, I would like to be able to do todays calendar on the top level pagel and
-Contributed [[plugins]]:
+These plugins are provided by third parties and are not currently
+included in ikiwiki. See [[install]] for installation help.
-(See [[install]] for installation help.)
-
-[[inline pages="plugins/contrib/* !*/Discussion"
+[[!inline pages="plugins/contrib/* and !*/Discussion"
feedpages="created_after(plugins/contrib/navbar)" archive="yes"
rootpage="plugins/contrib" postformtext="Add a new plugin named:" show=0]]
--- /dev/null
+[[!template id=plugin name=album author="[[Simon_McVittie|smcv]]"]]
+[[!template id=gitbranch branch=smcv/album author="[[Simon_McVittie|smcv]]"]]
+[[!tag type/chrome]]
+
+Available from [[smcv]]'s git repository, in the `album` branch
+([[users/smcv/gallery|users/smcv/gallery]] contains some older
+thoughts about this plugin).
+
+This plugin formats a collection of images into a photo album,
+in the same way as many websites: good examples include the
+PHP application [Gallery](http://gallery.menalto.com/), Flickr,
+and Facebook's Photos "application". I've called it `album`
+to distinguish it from [[contrib/gallery|plugins/contrib/gallery]],
+although `gallery` might well be a better name for this functionality.
+
+The web UI I'm trying to achieve consists of one
+[HTML page of thumbnails](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/)
+as an entry point to the album, where each thumbnail links to
+[a "viewer" HTML page](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/img_0068/)
+with a full size image, next/previous thumbnail links, and
+[[plugins/comments]].
+
+(The Summer of Code [[plugins/contrib/gallery]] plugin does the
+next/previous UI in Javascript using Lightbox, which means that
+individual photos can't be bookmarked in a meaningful way, and
+the best it can do as a fallback for non-Javascript browsers
+is to provide a direct link to the image.)
+
+## Writing the viewers
+
+ \[[!albumimage image=foo.jpg album=myalbum
+ title=...
+ caption=...
+ copyright=...
+ size=...
+ viewertemplate=...
+ ]]
+
+Each viewer contains one `\[[!albumimage]]` directive. This
+sets the `image` filename, the `album` in which this image appears,
+and an optional `caption`, and can override the `size` at which to
+display the image and the `viewertemplate` to use to display the
+image.
+
+It can also have `title`, `copyright` and `date` parameters, which
+are short-cuts for [[ikiwiki/directive/meta]] directives.
+
+The viewer can also have any other content, but typically the
+directive will be the only thing there.
+
+Eventually, there will be a specialized CGI user interface to
+edit all the photos of an album at once, upload a new photo
+(which will attach the photo but also write out a viewer page
+for it), or mark an already-uploaded photo as a member of an
+album (which is done by writing out a viewer page for it).
+
+The `\[[!albumimage]]` directive is replaced by an
+[[ikiwiki/directive/img]], wrapped in some formatting using a
+template (by default `albumviewer.tmpl`). The template can (and
+should) also include "next photo", "previous photo" and
+"up to gallery" links.
+
+The next/previous links are themselves implemented by
+[[inlining|ikiwiki/directive/inline]] the next or previous
+photo, using a special template (by default `albumnext.tmpl`
+or `albumprev.tmpl`), in `archive`/`quick` mode.
+
+> With hindsight, using an inline here is wrong - I should just
+> run hooks and fill in the template within the album plugin.
+> inline has some specialized functionality that's overkill
+> here, and its delayed HTML substitution breaks the ability
+> to have previous/up/next links both above and below the
+> photo, for instance. --[[smcv]]
+
+## Writing the album
+
+The album contains one `\[[!album]]` directive. It may also
+contain any number of `\[[!albumsection]]` directives, for
+example the demo album linked above could look like:
+
+ \[[!album]]
+ <!-- replaced with one uncategorized photo -->
+
+ ## Gamarra
+
+ \[[!albumsection filter="link(gamarra)"]]
+ <!-- all the Gamarra photos -->
+
+ ## Smokescreen
+
+ \[[!albumsection filter="link(smokescreen)"]]
+ <!-- all the Smokescreen photos -->
+
+ ...
+
+The `\[[!album]]` directive is replaced by an
+[[ikiwiki/directive/inline]] which automatically includes every
+page that has an `\[[!albumimage]]` directive linking it to this
+album, except those that will appear in an `\[[!albumsection]]`.
+
+The `inline` is in `archive`/`quick` mode, but includes some
+extra information about the images, including file size and a
+thumbnail (again, made using [[ikiwiki/directive/img]]). The
+default template is `albumitem.tmpl`, which takes advantage
+of these things.
+
+Each `\[[!albumsection]]` is replaced by a similar inline, which
+selects a subset of the photos in the album.
-[[template id=plugin name=attach author="[[Ben]]"]]
+[[!template id=plugin name=attach author="[[Ben]]"]]
**Note: This plugin is currently pending upload. It is also most assuredly beta.**
--- /dev/null
+[[!template id=plugin name=cvs core=0 author="[[schmonz]]"]]
+
+[[!template id=gitbranch branch=schmonz author="[[schmonz]]"]]
+
+This plugin allows ikiwiki to use [[!wikipedia desc="CVS" Concurrent Versions System]] as an [[rcs]].
+
+### Usage
+7. Install [cvsps](http://www.cobite.com/cvsps/), [[!cpan IPC::Cmd]], [[!cpan String::ShellQuote]], and [cvsweb](http://www.freebsd.org/projects/cvsweb.html) or the like.
+7. Adjust CVS-related parameters in your setup file.
+
+Consider creating `$HOME/.cvsrc` if you don't have one already; the plugin doesn't need it, but you yourself might. Here's a good general-purpose one:
+
+ cvs -q
+ checkout -P
+ update -dP
+ diff -u
+ rdiff -u
+
+### Implementation details
+* `cvs.pm` started life as a copy of [[3.14159|news/version_3.14159]]'s `svn.pm`.
+* `IkiWiki.pm:wiki_file_prune_regexps` avoids copying CVS metadata into `$DESTDIR`.
+* [[ikiwiki-makerepo]]:
+ * creates a repository,
+ * imports `$SRCDIR` into top-level module `ikiwiki` (vendor tag IKIWIKI, release tag PRE_CVS),
+ * configures the post-commit hook in `CVSROOT/loginfo`.
+* CVS multi-directory commits happen separately; the post-commit hook sees only the first directory's changes in time for [[recentchanges|plugins/recentchanges]]. The next run of `ikiwiki --setup` will correctly re-render such a recentchanges entry. It should be possible to solve this problem with NetBSD's `commit_prep` and `log_accum` scripts (see below).
+
+### To do
+* Add automated tests. (Blindly adding svn-like tests to `t/file_pruned.t` doesn't do the trick.)
+* If the argument to `cvs add` smells like a binary file, `cvs add -kb` it (for [[plugins/attachment]] support).
+* Don't slurp the entire `cvsps` output into memory (!).
+* Instead of resource-intensively scraping changesets with `cvsps`, have `ikiwiki-makerepo` set up NetBSD-like `log_accum` and `commit_prep` scripts that coalesce and keep records of commits. `cvsps` can be used as a fallback for repositories without such records.
+* Perhaps prevent web edits from attempting to create `.../CVS/foo.mdwn` (and `.../cvs/foo.mdwn` on case-insensitive filesystems); thanks to the CVS metadata directory, the attempt will fail anyway (and much more confusingly) if we don't.
--- /dev/null
+I've started reviewing this, and the main thing I don't like is the
+post-commit wrapper wrapper that ikiwiki-makerepo is patched to set up.
+That just seems unnecessarily complicated. Why can't ikiwiki itself detect
+the "cvs add <directory>" call and avoid doing anything in that case?
+--[[Joey]]
+
+> The wrapper wrapper does three things:
+>
+> 7. It ignores `cvs add <directory>`, since this is a weird CVS
+> behavior that ikiwiki gets confused by and doesn't need to act on.
+> 7. It prevents `cvs` locking against itself: `cvs commit` takes a
+> write lock and runs the post-commit hook, which runs `cvs update`,
+> which wants a read lock and sleeps forever -- unless the post-commit
+> hook runs in the background so the commit can "finish".
+> 7. It fails silently if the ikiwiki post-commit hook is missing.
+> CVS doesn't have any magic post-commit filenames, so hooks have to
+> be configured explicitly. I don't think a commit will actually fail
+> if a configured post-commit hook is missing (though I can't test
+> this at the moment).
+>
+> Thing 1 can probably be handled within ikiwiki, if that seems less
+> gross to you.
+
+>> It seems like it might be. You can use a `getopt` hook to check
+>> `@ARGV` to see how it was called. --[[Joey]]
+
+>>> This does the trick iff the post-commit wrapper passes its args
+>>> along. Committed on my branch. This seems potentially dangerous,
+>>> since the args passed to ikiwiki are influenced by web commits.
+>>> I don't see an exploit, but for paranoia's sake, maybe the wrapper
+>>> should only be built with execv() if the cvs plugin is loaded?
+>>> --[[schmonz]]
+
+>>>> Hadn't considered that. While in wrapper mode the normal getopt is not
+>>>> done, plugin getopt still runs, and so any unsafe options that
+>>>> other plugins support could be a problem if another user runs
+>>>> the setuid wrapper and passes those options through. --[[Joey]]
+
+>>>>> I've tried compiling the argument check into the wrapper as
+>>>>> the first thing main() does, and was surprised to find that
+>>>>> this doesn't prevent the `cvs add <dir>` deadlock in a web
+>>>>> commit. I was convinced this'd be a reasonable solution,
+>>>>> especially if conditionalized on the cvs plugin being loaded,
+>>>>> but it doesn't work. And I stuck debug printfs at the beginning
+>>>>> of all the rcs_foo() subs, and whatever `cvs add <dir>` is
+>>>>> doing to ikiwiki isn't visible to my plugin, because none of
+>>>>> those subs are getting called. Nuts. Can you think of anything
+>>>>> else that might solve the problem, or should I go back to
+>>>>> generating a minimal wrapper wrapper that checks for just
+>>>>> this one thing? --[[schmonz]]
+
+>>>>>> I don't see how there could possibly be a difference between
+>>>>>> ikiwiki's C wrapper and your shell wrapper wrapper here. --[[Joey]]
+
+> Thing 2 I'm less sure of. (I'd like to see the web UI return
+> immediately on save anyway, to a temporary "rebuilding, please wait
+> if you feel like knowing when it's done" page, but this problem
+> with CVS happens with any kind of commit, and could conceivably
+> happen with some other VCS.)
+
+>> None of the other VCSes let a write lock block a read lock, apparently.
+>>
+>> Anyway, re the backgrounding, when committing via the web, the
+>> post-commit hook doesn't run anyway; the rendering is done via the
+>> ikiwiki CGI. It would certianly be nice if it popped up a quick "working"
+>> page and replaced it with the updated page when done, but that's
+>> unrelated; the post-commit
+>> hook only does rendering when committing using the VCS directly. The
+>> backgrounding you do actually seems safe enough -- but tacking
+>> on a " &" to the ikiwiki wrapper call doesn't need a wrapper script,
+>> does it? --[[Joey]]
+
+>>> Nope, it works fine to append it to the `CVSROOT/loginfo` line.
+>>> Fixed on my branch. --[[schmonz]]
+
+> Thing 3 I think I did in order to squelch the error messages that
+> were bollixing up the CGI. It was easy to do this in the wrapper
+> wrapper, but if that's going away, it can be done just as easily
+> with output redirection in `CVSROOT/loginfo`.
+>
+> --[[schmonz]]
+
+>> If the error messages screw up the CGI they must go to stdout.
+>> I thought we had stderr even in the the CVS dark ages. ;-) --[[Joey]]
+
+>>> Some messages go to stderr, but definitely not all. That's why
+>>> I wound up reaching for IPC::Cmd, to execute the command line
+>>> safely while shutting CVS up. Anyway, I've tested what happens
+>>> if a configured post-commit hook is missing, and it seems fine,
+>>> probably also thanks to IPC::Cmd.
+>>> --[[schmonz]]
-[[template id=plugin name=copyright author="[[tschwinge]]"]]
-[[template id=plugin name=license author="[[tschwinge]]"]]
+[[!template id=plugin name=copyright author="[[tschwinge]]"]]
+[[!template id=plugin name=license author="[[tschwinge]]"]]
-[[meta title="default content for *copyright* and *license*"]]
+[[!meta title="default content for *copyright* and *license*"]]
Someone was just asking for it and I had written these two plugins already some months ago,
so I'm now publishing them here.
-<http://www.schwinge.homeip.net/~thomas/tmp/copyright.pm>
-<http://www.schwinge.homeip.net/~thomas/tmp/license.pm>
+[`copyright.pm`](http://www.schwinge.homeip.net/~thomas/tmp/copyright.pm)
+and
+[`license.pm`](http://www.schwinge.homeip.net/~thomas/tmp/license.pm)
-/!\ Note that there is still an issue to be resolved with these plugins: have a look at
-[tmpfs](http://www.bddebian.com/~wiki/hurd/translator/tmpfs/). There are two inlined pages,
-[tmpfs-notes\_bing](http://www.bddebian.com/~wiki/hurd/translator/tmpfs/notes_bing/) and
-[tmpfs-notes\_various](http://www.bddebian.com/~wiki/hurd/translator/tmpfs/notes_various/).
-Compare the *copyright* and *license* information of the inlined pages on *tmpfs* to those
-on the source pages, *tmpfs-notes_bing* and *tmpfs-notes_various*.
-They are different, but shouldn't be.
+Usage instructions are found inside the two plugin files.
--[[tschwinge]]
--[[bma]]
Copyright and license values are not "template values", they are values
-tracked by the meta plugin, and that various code compares and uses to fill
+tracked by the [[meta]] plugin, and that various code compares and uses to fill
out the templates. Something like varioki cannot do that. --[[Joey]]
+
+Somewhat more detailed usage documentation would be appreciated. I tried to setup
+those plugins with a current ikiwiki release, i.e. 2.61, but they appeared to do
+nothing, really. Also, those example pages don't seem to use those plugins, even;
+they set "copyright" and "license" properties using ordinary [[meta]] tags. Maybe
+I'm missing something terribly obvious? --Peter
+
+> Only obvious if you read the source :-). You need to put a file named "copyright.html"
+>(respectively "license.html") in your wiki. Everything underneath that (in the wikilink sense) will use that
+>content for the license or copyright. Saves putting \[[meta license="foo"]] in every page [[DavidBremner]]
+
+By the way: these need not be *HTML* files; `copyright.mdwn`,
+respectively `license.mdwn`, or every other format supported
+by ikiwiki are likewise fine. --[[tschwinge]]
+
+> Jon has done something similar in [[todo/allow_site-wide_meta_definitions]];
+> his version has the advantages that it doesn't invent magical page names,
+> and can extend beyond just copyright and license, but has the disadvantage
+> that it doesn't support setting defaults for a given "subdirectory"
+> only. --[[smcv]]
-[[template id=plugin name=gallery author="[[arpitjain]]"]]
+[[!template id=plugin name=gallery author="[[arpitjain]]"]]
This plugin would create a nice looking gallery of the images. It has been build over the img plugin in Ikiwiki
-SVN repository of plugin is located at <http://ned.snow-crash.org:8080/svn/ikiwiki-gallery>
+GIT repo of the plugin is located at <http://github.com/joeyh/ikiwiki/tree/gallery>
USAGE :
-\[[gallery imagedir="images" option="value"]]
+\[[!gallery imagedir="images" option="value"]]
Available options : <br>
* imagedir(required) => Directory containing images. It will scan all the files with jpg|png|gif extension from the directory and will put it in the gallery.<br>
For any feedback or query, feel free to mail me at arpitjain11 [AT] gmail.com
Additional details are available [here](http://myweb.unomaha.edu/~ajain/ikiwikigallery.html).
+> That link is broken. --[[JosephTurian]]
-- [[arpitjain]]
-[[tag plugins]] [[tag patch]] [[tag soc]] [[tag wishlist]]
+[[!tag plugins]] [[!tag patch]] [[!tag soc]] [[!tag wishlist]]
However, I can't even get simply things like this to work:
$ cat web/index.mdwn
- [[gallery imagedir="b" vcs="0"]]
+ [[!gallery imagedir="b" vcs="0"]]
$ ls web/b/
1.jpg 2.jpg 3.jpg 4.jpg
$ ikiwiki [...] --plugin gallery web web.rendered
[...]
$ grep gallery web.rendered/index.html
- <p>[[gallery Failed to Read Directory b.]]</p>
+ <p>[[!gallery Failed to Read Directory b.]]</p>
When using `vcs="1"` it's no better:
Its probably because of the restriction of permissions by plugins in newer version of IkiWiki.
For the time being, you can turn resizing off till I look into conditional underlay directory feature.
-USAGE : [[gallery imagedir="directory" resize="0"]]
+USAGE : [[!gallery imagedir="directory" resize="0"]]
New version updated at SVN REPO : http://ned.snow-crash.org:8080/svn/ikiwiki-gallery/
-[[template id=plugin name=googlemaps author="Christian Mock"]]
-[[tag type/special-purpose todo/geotagging]]
+[[!template id=plugin name=googlemaps author="Christian Mock"]]
+[[!tag type/special-purpose todo/geotagging]]
`googlemaps` is a plugin that allows using the [Google Maps API][2]
from ikiwiki.
-[[template id=plugin name=headinganchors author="[[PaulWise]]"]]
+[[!template id=plugin name=headinganchors author="[[PaulWise]]"]]
-This is a simple plugin to add ids to all headings, based on their text. It
+This is a simple plugin to add ids (which will serve as [[anchor]]s) to all headings, based on their text. It
works as a postprocessing filter, allowing it to work on mdwn, wiki, html,
rst and any other format that produces html. The code is available here:
use strict;
use IkiWiki 2.00;
- sub import { #{{{
+ sub import {
hook(type => "sanitize", id => "headinganchors", call => \&headinganchors);
- } # }}}
+ }
sub text_to_anchor {
my $str = shift;
return $str;
}
- sub headinganchors (@) { #{{{
+ sub headinganchors (@) {
my %params=@_;
my $content=$params{content};
$content=~s{<h([0-9])>([^>]*)</h([0-9])>}{'<h'.$1.' id="'.text_to_anchor($2).'">'.$2.'</h'.$3.'>'}gie;
return $content;
- } # }}}
+ }
1
--- /dev/null
+Isn't this functionality a part of what [[plugins/toc]] needs and does? Then probably the [[plugins/toc]] plugin's code could be split into the part that implements the [[plugins/contrib/headinganchors]]'s functionality and the TOC generation itself. That will bring more order into the code and the set of available plugins. --Ivan Z.
+[[!template id=plugin name=highlightcode author="[[sabr]]"]]
+[[!tag type/format]]
+
A small plugin to allow Ikiwiki to display source files complete with syntax highlighting. Files with recognized extensions (i.e. my-file.cpp) are be rendered just like any other Ikiwiki page. You can even edit your source files with Ikiwiki's editor.
It uses the Syntax::Highlight::Engine::Kate Perl module to do the highlighting.
-[[template id=plugin name=img author="Christian Mock"]]
-[[tag type/chrome]]
+[[!template id=plugin name=img author="Christian Mock"]]
+[[!tag type/chrome]]
`img` is an enhanced image handling plugin.
and use the plugin once per page? Something like this on the first one if
it's got multiple clickable thumbnails:
- \[[img foo.jpg width=256 link=page2]]
+ \[[!img foo.jpg width=256 link=page2]]
This on the second:
- \[[img foo.jpg width=1024 link=page3]]
+ \[[!img foo.jpg width=1024 link=page3]]
\[[small|page1]]
\[[medium|page2]]
\[[large|page3]]
This on the third:
- \[[img foo.jpg link=page3]]
+ \[[!img foo.jpg link=page3]]
\[[small|page1]]
\[[medium|page2]]
\[[large|parge3]]
-[[template id=plugin name=linguas author="Jordà Polo"]]
+[[!template id=plugin name=linguas author="Jordà Polo"]]
Linguas
=======
Note that even though it is still available for download, this plugin is no
longer actively maintained. If you are interested in multilingual wiki pages, you
-can also take a look at other approaches such as [[todo/l10n]] or Lars Wirzenius's
+can also take a look at other approaches such as [[todo/l10n]], [[plugins/po]],
+or Lars Wirzenius's
[Static website, with translations, using IkiWiki](http://liw.iki.fi/liw/log/2007-05.html#20070528b).
Usage
`pagename.$LANG`, where `$LANG` is a ISO639-1 (two-letter) language code.
To enable linguas, add the following line in the source code of the page:
- \[[linguas ]]
+ \[[!linguas ]]
Note that linguas is only required in one of the pages (the original,
for instance); the rest of translations will be automatically
updated. Additionally, it is also possible to specify the title of
the translation:
- \[[linguas title="Translated title"]]
+ \[[!linguas title="Translated title"]]
Template
+ push @links, IkiWiki::htmllink($page, $destpage, $trans, noimageinline => 0, forcesubpage => 0, linktext => $link);
}
- my $otherlinguas = 'Translations:';
\ No newline at end of file
+ my $otherlinguas = 'Translations:';
--- /dev/null
+[[!template id=plugin name=mailbox author="[[DavidBremner]]"]]
+[[!tag type/format]]
+
+The `mailbox` plugin adds support to ikiwiki for
+rendering mailbox file into a page displaying the mails
+in the mailbox. It supports mbox, maildir, and MH folders,
+does threading, and deals with MIME.
+
+One hitch I noticed was that it is not currently possible to treat a
+maildir or an MH directory as a page (i.e. just call it foo.mh and have it
+transformed to page foo). I'm not sure if this is possible and worthwhile
+to fix. It is certainly workable to use a [[!mailbox ]] directive.
+-- [[DavidBremner]]
+
+This plugin is not in ikiwiki yet, but can be downloaded
+from <http://pivot.cs.unb.ca/git/ikimailbox.git>
+
+
--- /dev/null
+# The remote repo
+
+For some reason, `git fetch` from http://pivot.cs.unb.ca/git/ikimailbox.git/ didn't work very smoothly for me: it hung, and I had to restart it 3 times before the download was complete.
+
+I'm writing this just to let you know that there might be some problems with such connections to your http-server. --Ivan Z.
--- /dev/null
+[[!template id=plugin name=mediawiki author="[[sabr]]"]]
+[[!tag type/format]]
+
+[The Mediawiki plugin](http://u32.net/Mediawiki_Plugin/) allows ikiwiki to
+process pages written using MediaWiki markup.
+
+Available at <http://alcopop.org/~jon/mediawiki.pm>
--- /dev/null
+Anyone know a safe place where this plugin can be found? -- mjr at phonecoop.coop
+
+> I ended up doing a backassward way of doing it, as described at the [convert discussion page](http://ikiwiki.info/tips/convert_mediawiki_to_ikiwiki/discussion/). -[[simonraven]]
+
+>> I've mirrored it at <http://alcopop.org/~jon/mediawiki.pm>. -- [[Jon]]
-[[template id=plugin name=navbar author="[[TobiOetiker]]"]]
+[[!template id=plugin name=navbar author="[[TobiOetiker]]"]]
The Navbar Plugin renders a Navigation Bar into your page. It is based on code
from the [[sidebar_plugin|plugins/sidebar]].
--- /dev/null
+Where can I download this plugin ?
+-- [[jogo]]
--- /dev/null
+[[!template id=plugin name=opml author="[[JanWalzer|jwalzer]]"]]
+[[!tag type/format]]
+
+The idea of this plugin is to parse in an OPML-File and output a linklist, maybe some customization.
+OPML-Files are xml-files that most RSS-Readers write out, to summarize their subscribes feedlist.
+
+I have a "dumb" perlscript running on my website, that tries to do a opml2mdwn transformation, but its quite bad on that.
+
+This Plugin is **NOT Ready** in any way. I'm just putting this page up as a hook, to discuss it.
+
+I intend to work on this, but I'd appreciate any help on this.
--- /dev/null
+If this is the wrong place for the development of the plugin, please mode it on to a more appropriate one.
+
+Currently I'm quite stuck with the perl-stuff itself. I'm trying to become comfortable with the language, but it seems, the language doesn't like me. I'm lost in complex datastructures, when trying to iterate through the output of XML::Simple. --[[Jan|jwalzer]]
+
--- /dev/null
+[[!template id=plugin name=postal author="[[DavidBremner]]"]]
+[[!tag type/useful]]
+
+The `postal` plugin allows users to send mail to
+a special address to comment on a page. It uses the [[mailbox]]
+plugin to display their comments in the wiki.
+
+This plugin is not in ikiwiki yet, but can be downloaded
+from <http://pivot.cs.unb.ca/git/ikipostal.git>
+
+Details:
+
+ * Adds a mailto: url to each page matching some pagespec
+ (currently every page gets a comment footer)
+
+ * This mailto url goes to an address identifying the page (something like
+ user-iki-blog~I\_hate\_markdown@host.fqdn.tld).
+ [more details](http://www.cs.unb.ca/~bremner/blog/posts/encoding)
+
+ * on the mail receiving end, these messages are either deleted, or ran through
+ a filter to be turned into blog posts. I have
+[written](http://pivot.cs.unb.ca/git/?p=ikipostal.git;a=blob_plain;f=filters/postal-accept.pl;hb=HEAD)
+ a filter that decodes the address and writes the message into an appropriate
+mailbox. The changes are then checked into version control; typically a hook then updates the html version of the wiki.
+ * work in progress can be
+
+ - [cloned](http://pivot.cs.unb.ca/git/ikipostal.git), or
+ - [browsed](http://pivot.cs.unb.ca/git/?p=ikipostal.git;a=summary)
+
+ * I would be interested in any ideas people have about security.
+
+The current version of this plugin is now running on my home page. See for example
+[a recent post in my blog](http://www.cs.unb.ca/~bremner/blog/posts/can-i-haz-a-distributed-rss/).
+Unfortunately although the [[mailbox|todo/mbox]] renderer supports threading, I haven't had
+a chance to implement comments on comments yet. --[[DavidBremner]]
--- /dev/null
+It seems like the filter 'postal-accept.pl' I wrote doesn't refresh thoroughly enough. When a comment is added it calls
+
+ IkiWiki::add_depends($page,$comments_page);
+
+And then after adding the actual comment, it ends with
+
+ IkiWiki::refresh();
+ IkiWiki::saveindex();
+
+Sure enough, the page being commented on is refreshed, but not any inline pages (e.g. tags pages, blog top level) that contain it.
+Is there a way to recursively refresh? Or should it work that way by default. I guess it is some part of the api that I don't understand,
+since I think not many people grub about in the internals of ikiwiki this way.
+It would be nice to figure this out, doing a full rebuild every time I get a blog comment is not that fun.
+
+[[DavidBremner]]
+
+> Ikiwiki currently doesn't have support for transitive dependencies.
+> This is discussed deep inside [[todo/tracking_bugs_with_dependencies]]
+> and in [[todo/inlines_inheriting_links]].
+>
+> FYI, the [[plugins/comments]] plugin avoids this problem by only showing the
+> comments on the page, and not on pages that inline it. --[[Joey]]
+>> Ok, thanks for the speedy response. I guess I should do the same thing.
+>> [[DavidBremner]]
--- /dev/null
+[[!template id=plugin name=rsync core=0 author="[[schmonz]]"]]
+
+[[!template id=gitbranch branch=schmonz author="[[schmonz]]"]]
+
+This plugin allows ikiwiki to push generated pages to another host
+by running a command such as `rsync`.
+
+### Usage
+7. Enable automated SSH key exchange between ikiwiki and the remote
+ host. [keychain](http://www.gentoo.org/proj/en/keychain/) makes
+ it easy to use a passphrase-protected key for this purpose. It's
+ also a good idea to specify the exact command line to be permitted
+ in the remote host's `$HOME/.ssh/authorized_keys`.
+7. Set `rsync_command` in your setup file. If you're using a
+ passphrase-protected key, then set `rsync_command` to a shell
+ script which reads `keychain`'s current state before calling
+ `rsync`.
+
+### Implementation details
+* The plugin relies on a new "postrefresh" hook called at the very end of
+ `IkiWiki/Render.pm:refresh()`.
--- /dev/null
+## A use case
+
+Why I needed this plugin: I have two web servers available to me
+for a project. Neither does everything I need, but together they
+do. (This is a bit like the [Amazon S3
+scenario](http://kitenet.net/~joey/blog/entry/running_a_wiki_on_Amazon_S3/).)
+
+Server (1) is a university web server. It provides plentiful space
+and bandwidth, easy authentication for people editing the wiki, and
+a well-known stable URL. The wiki really wants to live here and
+very easily could except that the server doesn't allow arbitrary
+CGIs.
+
+Server (2) is provided by a generous alumnus's paid [[tips/DreamHost]]
+account. Disk and particularly network usage need to be minimized
+because over some threshold it costs him. CGI, etc. are available.
+
+My plan was to host the wiki on server (1) by taking advantage of
+server (2) to store the repository, source checkout, and generated
+pages, to host the repository browser, and to handle ikiwiki's CGI
+operations. In order for this to work, web edits on (2) would need
+to automatically push any changed pages to (1).
+
+As a proof of concept, I added an rsync post-commit hook after
+ikiwiki's usual. It worked, just not for web edits, which is how
+the wiki will be used. So I wrote this plugin to finish the job.
+The wiki now lives on (1), and clicking "edit" just works. --[[schmonz]]
+
+> Just out of interest, why use `rsync` and not `git push`. i.e. a
+> different setup to solve the same problem would be to run a
+> normal ikiwiki setup on the universities server with its git
+> repository available over ssh (same security setup your using
+> for rsync should work for git over ssh). On the cgi-capable server,
+> when it would rsync, make it git push. It would seem that git
+> has enough information that it should be able to be more
+> network efficient. It also means that corruption at one end
+> wouldn't be propagated to the other end. -- [[Will]]
+
+>> Hey, that's a nice solution. (The site was in svn to begin with,
+>> but it's in git now.) One advantage of my approach in this particular
+>> case: server (1) doesn't have `git` installed, but does have `rsync`,
+>> so (1)'s environment can remain completely untweaked other than the
+>> SSH arrangement. I kind of like that all the sysadmin effort is
+>> contained on one host.
+>>
+>> This plugin is definitely still useful for projects not able to use
+>> a DVCS (of which I've got at least one other), and possibly for
+>> other uses not yet imagined. ;-) --[[schmonz]]
-[[template id=plugin name=sar author="[[VictorMoral]]"]]
-[[tag type/chrome type/slow ]]
+[[!template id=plugin name=sar author="[[VictorMoral]]"]]
+[[!tag type/chrome type/slow ]]
The `sar` plugin is useful to make global or local search and replace operations
using common or specific terms.
## Sites and projects
- - [[sar search="ikiwiki" first="[IkiWiki](http://ikiwiki.info)" next="_IkiWiki_"]]
- - [[sar search="debian" first="[Debian](http://debian.org)" next="_Debian_"]]
- - [[sar search="perl" first="[Perl](http://perl.org)" next="_Perl_"]]
- - [[sar search="linux" replace="GNU/Linux"]]
+ - [[!sar search="ikiwiki" first="[IkiWiki](http://ikiwiki.info)" next="_IkiWiki_"]]
+ - [[!sar search="debian" first="[Debian](http://debian.org)" next="_Debian_"]]
+ - [[!sar search="perl" first="[Perl](http://perl.org)" next="_Perl_"]]
+ - [[!sar search="linux" replace="GNU/Linux"]]
## Persons
- - [[sar search="joey" first="[Joey Hess](http://ikiwiki.info/users/joey]]" next="_Joey_" ]]
- - [[sar search="angel" first="[Angel](http://triptico.com)" next="Angel"]]
+ - [[!sar search="joey" first="[Joey Hess](http://ikiwiki.info/users/joey]]" next="_Joey_" ]]
+ - [[!sar search="angel" first="[Angel](http://triptico.com)" next="Angel"]]
## Technical terms
- - [[sar search="smtp" first="\[[wp SMTP]]" next="‘SMTP‘"]]
- - [[sar search="pop3" first="\[[wp POP3]]" next="’POP3’"]]
+ - [[!sar search="smtp" first="\[[!wp SMTP]]" next="‘SMTP‘"]]
+ - [[!sar search="pop3" first="\[[!wp POP3]]" next="’POP3’"]]
The search expressions must be surrounded by double dashes in a source ikiwiki
page, like this:
In a ikiwiki source page we can write this
- \[[sar search=debian replace="__Debian__"]]
+ \[[!sar search=debian replace="__Debian__"]]
for define a global replace for the term `--debian--` or
- \[[sar search=ibm first=’[IBM](http://www.ibm.com)’
+ \[[!sar search=ibm first=’[IBM](http://www.ibm.com)’
next="_IBM_"]]
to define a replace for the first match of the string `--ibm--` and a different
-[[template id=plugin name=siterel2pagerel author="[[PaulWise]]"]]
+[[!template id=plugin name=siterel2pagerel author="[[PaulWise]]"]]
This is a simple plugin to convert all site-relative links to page-relative
links (converts /foo into ../../../foo or similar). It works as a
use strict;
use IkiWiki 2.00;
- sub import { #{{{
+ sub import {
hook(type => "sanitize", id => "siterel2pagerel", call => \&siterel2pagerel);
- } # }}}
+ }
- sub siterel2pagerel (@) { #{{{
+ sub siterel2pagerel (@) {
my %params=@_;
my $baseurl=IkiWiki::baseurl($params{page});
my $content=$params{content};
$content=~s/(<img(?:\s+(?:class|id|width|height)\s*="?\w+"?)*)\s+src=\s*"\/([^"]*)"/$1 src="$baseurl$2"/mig;
# FIXME: do <script and everything else that can have URLs in it
return $content;
- } # }}}
+ }
1
I have implemented a simple wrapper around
[source-highlight](http://www.gnu.org/software/src-highlite/). You can find the latest version in
-[git](http://pivot.cs.unb.ca/git?p=ikiperl.git;a=blob_plain;f=IkiWiki/Plugin/sourcehighlight.pm;hb=HEAD).
+[git](http://pivot.cs.unb.ca/git?p=ikiplugins.git;a=blob_plain;f=IkiWiki/Plugin/sourcehighlight.pm;hb=HEAD).
You must specify `highlight_lang=>"foo,bar"` in your setup file.
where foo and bar are the (source-supported) languages you want to
highlight
### Issues
-- I would like to have a link to the raw source; using will_render() and then copying the file should work.
+- I would like to have a link to the raw source; using will_render() and then copying the file should work.
-- the common case of foo.c and foo.h breaks
-because they both generate page working/dir/foo.
-It looks to me like ikiwiki is hardcoded to strip the extension in `pagename()` (IkiWiki.pm).
-This problem with sourcehighlight needs to be fixed before it is very useful.
+> You might also like to look at the [[todo/source_link]] todo. -- [[Will]]
-[[DavidBremner]]
+- Is there a way to configure the colors used by source-highlight (other than editing the globally installed "default.style" file)? It would help if I could pass the command arbitrary command-line arguments; then I could configure which config file it's supposed to use. For instance, I'm not a fan of hard-coding the colors into the HTML output. IMHO, css-style formatting should be preferred. All that can be set via the command line ... --Peter
+
+> I don't really have time right now, but it should be easy to add, if you look at how src-lang is handled. Patches are welcome :-) --[[DavidBremner]]
+
+Note that [[Will]] wrote a plugin that uses source-highlight also. It's
+available
+[[here|todo/automatic_use_of_syntax_plugin_on_source_code_files/discussion]].
+--[[Joey]]
+
+To be honest, [[Will]]'s version of this looks more polished. I will try his
+plugin and see if it can just replace mine. --[[DavidBremner]]
+
+
+*Updated* Now uses keepextension so multiple extensions should be OK
-[[template id=plugin name=syntax author="[[VictorMoral]]"]]
-[[tag type/chrome type/slow]]
+[[!template id=plugin name=syntax author="[[VictorMoral]]"]]
+[[!tag type/chrome type/slow]]
-The `syntax` plugin adds support to ikiwiki for syntax highlighting through the *vim* editor and its perl interface [[cpan Text::VimColor]]. It depends on a functional vim installation.
+The `syntax` plugin adds support to ikiwiki for syntax highlighting through the *vim* editor and its perl interface [[!cpan Text::VimColor]]. It depends on a functional vim installation.
The plugin inserts a fragment of HTML with special marks from a file or a string text. It accepts the following parameters:
Example:
- \[[syntax type="perl" text="""
+ \[[!syntax type="perl" text="""
#!/usr/bin/perl
my $a = "World";
or
- \[[syntax file="/examples/hello.pl" description="My first perl program"]]
+ \[[!syntax file="/examples/hello.pl" description="My first perl program"]]
This plugin create the following CSS styles:
my old tex4ht based home page, it seems to work OK.
The current version is available from
-[git](http://pivot.cs.unb.ca/git?p=ikiperl.git;a=blob_plain;f=IkiWiki/Plugin/tex4ht.pm;hb=HEAD)
+[git](http://pivot.cs.unb.ca/git?p=ikiplugins.git;a=blob_plain;f=IkiWiki/Plugin/tex4ht.pm;hb=HEAD)
### Other related ideas/plugins:
-- [[todo/latex]] There is work in progress at converting snippets of latex. No idea how the hybrid approach of tex4ht (part fonts, part bitmaps) compares to the [[todo/latex]] approach.
+- [[todo/latex]] There is work in progress at converting snippets of latex. No idea how the hybrid approach of tex4ht (part font, part bitmaps) compares to the [[todo/latex]] approach.
- pandoc can also convert latex to html or markdown. It is much faster than tex4ht; on the other hand, the rendering quality is not quite as good, and pandoc does not understand user defined TeX macros.
-[[template id=plugin name=texinfo author="[[tschwinge]]"]]
+[[!template id=plugin name=texinfo author="[[tschwinge]]"]]
[[I|tschwinge]] started writing a plugin to render
[GNU Texinfo](http://www.gnu.org/software/texinfo/)
--- /dev/null
+[[!tag type/chrome patch]]
+[[!template id=gitbranch branch=smcv/trail author="[[smcv]]"]]
+
+Available from [[smcv]]'s git repository, in the `trail` branch. This
+plugin aims to solve [[todo/wikitrails]] in a simpler way.
+
+Joey: what do you think of this plugin? If you like the general approach
+and are likely to include it in ikiwiki, I'll try to modify
+[[plugins/contrib/album]] to be based on it, rather than partially
+reinventing it.
+
+Bugs:
+
+* \[[!inline pages="..." trail=yes]] currently tries to work out
+ what pages are in the trail, and their order, at scan time. That
+ won't work, because matching a pagespec at scan time is
+ unreliable - pages we want might not have been scanned yet! I
+ haven't worked out a solution for this. I think
+ \[[!inline pagenames="..." trail=yes]] would be safe, though.
+
+----
+
+[[!template id=plugin name=trail author="[[Simon_McVittie|smcv]]"]]
+
+It's sometimes useful to have "trails" of pages in a wiki, as a guided
+tour, sequence of chapters etc. In this plugin, a trail is represented
+by a page, and the pages in the trail are indicated by specially marked
+links within that page.
+
+If using the default `page.tmpl`, each page automatically displays the
+trails that it's a member of (if any), with links to the trail and to
+the next and previous members.
+
+The `traillink` [[ikiwiki/directive]] is used to record which pages
+are in a trail, and simultaneously link to them. Alternatively, the
+[[ikiwiki/directive/inline]] directive can be used with `trail=yes`
+to record the inlined pages as part of the trail, in the order in
+which they are inlined.
+
+## Directives
+
+(These will go to the appropriate pages in [[ikiwiki/directive]] if this
+plugin is included in ikiwiki.)
+
+### traillink
+
+The `traillink` directive is supplied by the [[!iki plugins/contrib/trail desc=trail]]
+plugin. This directive appears on the page representing a trail. It acts
+as a visible [[ikiwiki/WikiLink]], but also records the linked page as
+a member of the trail.
+
+Various syntaxes can be used:
+
+ \[[!traillink Badgers]]
+ \[[!traillink How_to_find_mushrooms_using_badgers|badgers]]
+ \[[!traillink badgers text="How to find mushrooms using badgers"]]
+
+### trailoptions
+
+The `trailoptions` directive is supplied by the [[!iki plugins/contrib/trail desc=trail]]
+plugin. This directive appears on the page representing a trail, and
+produces no output.
+
+Currently, the only option supported is `[[!trailoptions circular=yes]]`,
+which adds links between the first and last pages, turning the trail into
+a circle.
--- /dev/null
+[[!template id=plugin name=unixauth core=0 author="[[schmonz]]"]]
+[[!tag type/auth]]
+
+This plugin authenticates users against the Unix user database. It presents a similar UI to [[plugins/passwordauth]], but simpler, as there's no need to be able to register or change one's password.
+
+To authenticate, either [checkpassword](http://cr.yp.to/checkpwd.html) or [pwauth](http://www.unixpapa.com/pwauth/) must be installed and configured. `checkpassword` is strongly preferred. If your web server runs as an unprivileged user -- as it darn well should! -- then `checkpassword` needs to be setuid root. (Or your ikiwiki CGI wrapper, I guess, but don't do that.) Other checkpassword implementations are available, notably [checkpassword-pam](http://checkpasswd-pam.sourceforge.net/).
+
+Config variables that affect the behavior of `unixauth`:
+
+* `unixauth_type`: defaults to unset, can be "checkpassword" or "pwauth"
+* `unixauth_command`: defaults to unset, should contain the full path and any arguments
+* `unixauth_requiressl`: defaults to 1, can be 0
+* `sslcookie`: needs to be 1 if `unixauth_requiressl` is 1 (perhaps this should be done automatically?)
+
+__Security__: [As with passwordauth](/security/#index14h2), be wary of sending usernames and passwords in cleartext. Unlike passwordauth, sniffing `unixauth` credentials can get an attacker much further than mere wiki access. Therefore, this plugin defaults to not even _displaying_ the login form fields unless we're running under SSL. Nobody should be able to do anything remotely dumb until the admin has done at least a little thinking. After that, dumb things are always possible. ;-)
+
+`unixauth` needs the `HTTPS` environment variable, available in ikiwiki 2.67 or later (fixed in #[502047](http://bugs.debian.org/502047)), without which it fails closed.
+
+The plugin has not been tested with newer versions of ikiwiki. [[schmonz]] hopes to have time to polish this plugin soon.
+
+[[!toggle id="code" text="unixauth.pm"]]
+
+[[!toggleable id="code" text="""
+
+ #!/usr/bin/perl
+ # Ikiwiki unixauth authentication.
+ package IkiWiki::Plugin::unixauth;
+
+ use warnings;
+ use strict;
+ use IkiWiki 2.00;
+
+ sub import {
+ hook(type => "getsetup", id => "unixauth", call => \&getsetup);
+ hook(type => "formbuilder_setup", id => "unixauth",
+ call => \&formbuilder_setup);
+ hook(type => "formbuilder", id => "unixauth",
+ call => \&formbuilder);
+ hook(type => "sessioncgi", id => "unixauth", call => \&sessioncgi);
+ }
+
+ sub getsetup () {
+ return
+ unixauth_type => {
+ type => "string",
+ example => "checkpassword",
+ description => "type of authenticator; can be 'checkpassword' or 'pwauth'",
+ safe => 0,
+ rebuild => 1,
+ },
+ unixauth_command => {
+ type => "string",
+ example => "/path/to/checkpassword",
+ description => "full path and any arguments",
+ safe => 0,
+ rebuild => 1,
+ },
+ unixauth_requiressl => {
+ type => "boolean",
+ example => "1",
+ description => "require SSL? strongly recommended",
+ safe => 0,
+ rebuild => 1,
+ },
+ plugin => {
+ description => "Unix user authentication",
+ safe => 0,
+ rebuild => 1,
+ },
+ }
+
+ # Checks if a string matches a user's password, and returns true or false.
+ sub checkpassword ($$;$) {
+ my $user=shift;
+ my $password=shift;
+ my $field=shift || "password";
+
+ # It's very important that the user not be allowed to log in with
+ # an empty password!
+ if (! length $password) {
+ return 0;
+ }
+
+ my $ret=0;
+ if (! exists $config{unixauth_type}) {
+ # admin needs to carefully think over his configuration
+ return 0;
+ }
+ elsif ($config{unixauth_type} eq "checkpassword") {
+ open UNIXAUTH, "|$config{unixauth_command} true 3<&0" or die("Could not run $config{unixauth_type}");
+ print UNIXAUTH "$user\0$password\0Y123456\0";
+ close UNIXAUTH;
+ $ret=!($?>>8);
+ }
+ elsif ($config{unixauth_type} eq "pwauth") {
+ open UNIXAUTH, "|$config{unixauth_command}" or die("Could not run $config{unixauth_type}");
+ print UNIXAUTH "$user\n$password\n";
+ close UNIXAUTH;
+ $ret=!($?>>8);
+ }
+ else {
+ # no such authentication type
+ return 0;
+ }
+
+ if ($ret) {
+ my $userinfo=IkiWiki::userinfo_retrieve();
+ if (! length $user || ! defined $userinfo ||
+ ! exists $userinfo->{$user} || ! ref $userinfo->{$user}) {
+ IkiWiki::userinfo_setall($user, {
+ 'email' => '',
+ 'regdate' => time,
+ });
+ }
+ }
+
+ return $ret;
+ }
+
+ sub formbuilder_setup (@) {
+ my %params=@_;
+
+ my $form=$params{form};
+ my $session=$params{session};
+ my $cgi=$params{cgi};
+
+ # if not under SSL, die before even showing a login form,
+ # unless the admin explicitly says it's fine
+ if (! exists $config{unixauth_requiressl}) {
+ $config{unixauth_requiressl} = 1;
+ }
+ if ($config{unixauth_requiressl}) {
+ if ((! $config{sslcookie}) || (! exists $ENV{'HTTPS'})) {
+ die("SSL required to login. Contact your administrator.<br>");
+ }
+ }
+
+ if ($form->title eq "signin") {
+ $form->field(name => "name", required => 0);
+ $form->field(name => "password", type => "password", required => 0);
+
+ if ($form->submitted) {
+ my $submittype=$form->submitted;
+ # Set required fields based on how form was submitted.
+ my %required=(
+ "Login" => [qw(name password)],
+ );
+ foreach my $opt (@{$required{$submittype}}) {
+ $form->field(name => $opt, required => 1);
+ }
+
+ # Validate password against name for Login.
+ if ($submittype eq "Login") {
+ $form->field(
+ name => "password",
+ validate => sub {
+ checkpassword($form->field("name"), shift);
+ },
+ );
+ }
+
+ # XXX is this reachable? looks like no
+ elsif ($submittype eq "Login") {
+ $form->field(
+ name => "name",
+ validate => sub {
+ my $name=shift;
+ length $name &&
+ IkiWiki::userinfo_get($name, "regdate");
+ },
+ );
+ }
+ }
+ else {
+ # First time settings.
+ $form->field(name => "name");
+ if ($session->param("name")) {
+ $form->field(name => "name", value => $session->param("name"));
+ }
+ }
+ }
+ elsif ($form->title eq "preferences") {
+ $form->field(name => "name", disabled => 1,
+ value => $session->param("name"), force => 1,
+ fieldset => "login");
+ $form->field(name => "password", disabled => 1, type => "password",
+ fieldset => "login"),
+ }
+ }
+
+ sub formbuilder (@) {
+ my %params=@_;
+
+ my $form=$params{form};
+ my $session=$params{session};
+ my $cgi=$params{cgi};
+ my $buttons=$params{buttons};
+
+ if ($form->title eq "signin") {
+ if ($form->submitted && $form->validate) {
+ if ($form->submitted eq 'Login') {
+ $session->param("name", $form->field("name"));
+ IkiWiki::cgi_postsignin($cgi, $session);
+ }
+ }
+ }
+ elsif ($form->title eq "preferences") {
+ if ($form->submitted eq "Save Preferences" && $form->validate) {
+ my $user_name=$form->field('name');
+ }
+ }
+ }
+
+ sub sessioncgi ($$) {
+ my $q=shift;
+ my $session=shift;
+ }
+
+ 1
+
+"""]]
--- /dev/null
+The security of this plugin scares me. As noted in the plugin
+documentation, you basically have to use it with SSL, since snooping on the
+login password doesn't give you an essentially useless account -- it gives
+you an actual account on the machine!
+
+Also, apparently pwauth defers *all* auth attempts if one fails, and it
+does this by using a lock file, and sleeping after a failed auth attempt.
+Which is needed to avoid brute-forcing, since this is a significant
+password.. but how will that interact with ikiwiki? Well, ikiwiki _also_
+uses a lock file. So, at a minimum, someone can not only try to brute-force
+the pwauth password, but the ikiwiki processes that stack up due to that
+will also keep ikiwiki's lock held. Which basically DOSes the wiki for
+everyone else; noone else can try to log in, or log out, or edit a page,
+all of which require taking the lock.
+
+So I don't think I'll be accepting this plugin into ikiwiki itself..
+--[[Joey]]
+
+Thanks for the comments. That's definitely an undesirable interaction between pwauth and ikiwiki; in my current application it wouldn't be a serious problem, but I'd like this plugin to be general-purpose and safe enough for inclusion in ikiwiki. It's the system-users-are-wiki-users idea I'm married to here, not pwauth itself; can you suggest another approach I might take?
+-- [[schmonz]]
+
+> Have you considered using [[plugins/httpauth]] and then the appropriate apache module? There are apache modules like [mod_authnz_external](http://unixpapa.com/mod_auth_external.html) that might help. The advantage of these solutions is that they usually make the security implications explicit. -- Will
+
+Actually, yes. That's how I made sure I had pwauth working to begin with. I'm partial to the form-based approach because I'm not aware of any way to reliably "log out" browsers from HTTP authentication. If that *is* reliably possible, then I worked way too hard for no reason. ;-)
+-- [[schmonz]]
+
+I've added support for [checkpassword](http://cr.yp.to/checkpwd/interface.html), since those generally don't have any rate-limiting cleverness to interfere with ikiwiki's, and made a few other changes. Please check out the plugin docs again and let me know if this is closer to being acceptable.
+-- [[schmonz]]
+
+> I actually think that the rate limiting is a good thing. After all,
+> ikiwiki doesn't do its own login rate limiting. Just need to find a way
+> to disentangle the two locks. --[[Joey]]
+
+>> Ah, ok, I misunderstood your comment. I'll see what I can figure out. --[[schmonz]]
+
+>>> My time's been limited for this, but I just saw [[todo/avoid_thrashing]]. How does that interact with pwauth or checkpassword? --[[schmonz]]
+
+>>>> The DOS still happens, it just uses less memory. --[[Joey]]
--- /dev/null
+[[!template id=plugin name=unixrelpagespec core=0 author="[[Jogo]]"]]
+
+I don't understand why `./*` correspond to siblings and not subpages.
+This is probably only meaningfull with [[plugins/autoindex]] turned on.
+
+Here is a small plugin wich follow usual Unix convention :
+
+- `./*` expand to subpages
+- `../*` expand to siblings
+
+---
+ #!/usr/bin/perl
+ # UnixRelPageSpec plugin.
+ # by Joseph Boudou <jogo at matabio dot net>
+
+ package IkiWiki::Plugin::unixrelpagespec;
+
+ use warnings;
+ use strict;
+ use IkiWiki 3.00;
+
+ sub import {
+ inject(
+ name => 'IkiWiki::PageSpec::derel',
+ call => \&unix_derel
+ );
+ }
+
+ sub unix_derel ($$) {
+ my $path = shift;
+ my $from = shift;
+
+ if ($path =~ m!^\.{1,2}/!) {
+ $from =~ s#/?[^/]+$## if (defined $from and $path =~ m/^\.{2}/);
+ $path =~ s#^\.{1,2}/##;
+ $path = "$from/$path" if length $from;
+ }
+
+ return $path;
+ }
+
+ 1;
-[[template id=plugin name=creole author="BerndZeimetz"]]
-[[tag type/format]]
+[[!template id=plugin name=creole author="BerndZeimetz"]]
+[[!tag type/format]]
This plugin allows ikiwiki to process pages written in
[WikiCreole](http://www.wikicreole.org/) format.
-To use it, you need to have the [[cpan Text::WikiCreole]] perl
+To use it, you need to have the [[!cpan Text::WikiCreole]] perl
module installed, enable the plugin, then files with the extention `.creole`
will be processed as creole.
[CheatSheet](http://www.wikicreole.org/wiki/CheatSheet).
Links are standard [[WikiLinks|ikiwiki/WikiLink]]. Links and
-[[PreProcessorDirectives]] inside `{{{ }}}` blocks are still expanded,
-since this happens before the creole format is processed.
+[[directives|ikiwiki/directive]] inside `{{{ }}}` blocks are still expanded,
+since this happens before the creole format is processed. (You need to escape
+them manually, via \\\[[directives]], the ~ escaping of creole doesn't work on
+this.)
+
+The standard ikiwiki [[WikiLinks|ikiwiki/WikiLink]] is almost the same as Creole link, except that creole uses \[[pagename|description]] while ikiwiki uses \[[description|pagename]].
+
+
--- /dev/null
+I've installed Text::WikiCreole 0.05 and enabled the plugin, but I get an error when rebuilding the wiki: `Undefined subroutine &IkiWiki::Plugin::creole::creole_custombarelinks called at /usr/pkg-20080723/lib/perl5/vendor_perl/5.8.0/IkiWiki/Plugin/creole.pm line 23`. Is there a newer Text::WikiCreole I'm not finding online?
+-- [[schmonz]]
+
+> There's a patch in the debian package of libtext-wikicreole-perl that
+> adds that option. I'm not sure what the status of it being released
+> upstream is, though IIRC I was assured it would not be a problem.
+> --[[Joey]]
+
+>> I've added the patch to pkgsrc as well. Thanks. --[[schmonz]]
+
+>> Currently the creole plugin is included in ikiwiki but the ikiwiki deb (3.0.3) doesn't suggests libtext-wikicreole-perl. Why? --[[weakish]]
+
+>>> forgot, done now --[[Joey]]
+
+I'm moving over a really stinkingly old UseMod and creole seems the nearest match. I've worked out that Bare /Subpage links need to become \[\[Subpage\]\], and Top/Sub links need to be \[\[Top/Sub\]\] (or \[\[Top/Sub|Top/Sub\]\], to display in exactly the same way), but I'm stuck on generic hyperlinks. The creole cheat sheet says I should be able to do \[\[http://url.path/foo|LinkText\]\], but that comes out as a link to create the "linktext" page, and Markdown-style \[Link Text\](http://url.path/foo) just gets rendered as is. Any suggestions? --[[schmonz]]
--- /dev/null
+[[!template id=plugin name=cutpaste author="[[Enrico]]"]]
+[[!tag type/chrome]]
+
+This plugin provides the [[ikiwiki/directive/cut]],
+[[ikiwiki/directive/copy]] and [[ikiwiki/directive/paste]]
+[[directives|ikiwiki/directive]].
+With these directives you can store and recall pieces of text in a page.
-[[template id=plugin name=ddate author="[[Joey]]"]]
-[[tag type/fun]]
+[[!template id=plugin name=ddate author="[[Joey]]"]]
+[[!tag type/fun]]
+[[!tag type/date]]
Enables use of Discordian dates. `--timeformat` can be used to change
the date format; see `ddate(1)`.
-This plugin requires the [[cpan DateTime]] and
-[[cpan DateTime::Calendar::Discordian]] perl modules.
+This plugin requires the [[!cpan DateTime]] and
+[[!cpan DateTime::Calendar::Discordian]] perl modules.
>Allows embedding of graphviz graphs.
>Posted Mon, 09 Apr 2007 05:09:04 -0400
---MichaelRasmussen
\ No newline at end of file
+--MichaelRasmussen
+
+Any objections to listing plugins alphabetically rather than by creation date? (i.e. change the inline to have sort="title".)
+
+-- Will
+
+> Well, it's been done by Josh, but I do wonder if there wasn't value to
+> being able to look at the top of the page for new plugins? --[[Joey]]
+
+>> I agree, which is why I brought it up here rather than just changing it.
+>> On balance I think the alphabetical list is better. You could have a
+>> "recently changed" list with the 10 most recently changed plugins
+>> at the top. That would allow what you suggested, but still allow
+>> the main list to be alphabetical. -- [[Will]]
-[[template id=plugin name=editdiff author="[[JeremieKoenig]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=editdiff author="[[JeremieKoenig]]"]]
+[[!tag type/web]]
This plugin adds a "Diff" button when a page is being edited.
When clicked, a diff between the stored page and provided content
--- /dev/null
+I've enabled the plugin on an SVN-backed wiki, but am not seeing the Diff button when editing. (I do see the Rename and Remove buttons from having enabled those plugins.) Any ideas why it wouldn't be showing up? --[[schmonz]]
+
+> It was broken, I've fixed it. --[[Joey]]
+
+>> Awesome, thanks! --[[schmonz]]
--- /dev/null
+[[!template id=plugin name=editpage core=1 author="[[Joey]]"]]
+
+This plugin allows editing wiki pages in the web interface. It's enabled by
+default if [[cgi]] is enabled; disable it if you want cgi for other things
+while not allowing page edits.
-[[template id=plugin name=edittemplate author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=edittemplate author="[[Joey]]"]]
+[[!tag type/web]]
-This plugin allows registering template pages, that provide default
-content for new pages created using the web frontend. To register a
-template, insert a [[Preprocessor_Directive|/ikiwiki/preprocessordirective]] on some other page.
-
- \[[!edittemplate template="bugtemplate" match="bugs/*"]]
-
-In the above example, the page named "bugtemplate" is registered as a
-template to be used when any page named "bugs/*" is created.
-
-Often the template page contains a simple skeleton for a particular type of
-page. For the bug report pages in the above example, it might look
-something like:
-
- Package:
- Version:
- Reproducible: y/n
- Details:
-
-The template page can also contain [[cpan HTML::Template]] directives,
-similar to other ikiwiki [[templates]]. Currently only one variable is
-set: `<TMPL_VAR name>` is replaced with the name of the page being
-created.
-
-----
-
-It's generally not a good idea to put the `edittemplate` directive in
-the template page itself, since the directive would then be included as
-part of the template on new pages, which would then in turn be registered
-as templates. If multiple pages are registered as templates for a new page,
-an arbitrary one is chosen, so that could get confusing.
+This plugin provides the [[ikiwiki/directive/edittemplate]] [[ikiwiki/directive]].
+This directive allows registering template pages, that provide default
+content for new pages created using the web frontend.
-[[template id=plugin name=embed author="[[Joey]]"]]
-[[tag type/html]]
+[[!template id=plugin name=embed author="[[Joey]]"]]
+[[!tag type/html]]
This plugin allows embedding content from external sites on
wiki pages.
with "XXX"; everything else must appear exactly as shown to be accepted by the
plugin.
+**This plugin is deprecated.** Rather than relying on these complex lists
+of safe content, which constantly fall out of date, you're recommended to
+configure the [[htmlscrubber]] to not scrub some pages, which only trusted
+users can edit. Then you can embed anything from anywhere on those pages.
+See [[tips/embedding_content]] for details and examples.
+This plugin's lists of safe embedded content will not be maintained, and
+the plugin will be removed in a future release.
+
## google maps
Use html like this to embed a map:
-[[template id=plugin name=favicon author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=favicon author="[[Joey]]"]]
+[[!tag type/chrome]]
If this plugin is enabled, then an icon link is added to pages, for web
browsers to display. The icon is currently hardcoded to be a favicon.ico,
--- /dev/null
+[[!template id=plugin name=filecheck core=0 author="[[Joey]]"]]
+[[!tag type/useful]]
+
+This plugin enhances the regular [[ikiwiki/PageSpec]] syntax with
+some additional tests, for things like file size, mime type, and virus
+status. These tests are mostly useful for the [[attachment]] plugin, and
+are documented [[here|ikiwiki/pagespec/attachment]].
+
+This plugin will use the [[!cpan File::MimeInfo::Magic]] perl module, if
+available, for mimetype checking.
+
+The `virusfree` [[PageSpec|ikiwiki/pagespec/attachment]] requires that
+ikiwiki be configured with a virus scanner program via the `virus_checker`
+option in the setup file. If using `clamav`, with `clamd`, set it to
+"clamdscan -". Or to use clamav without the `clamd` daemon, you
+could set it to "clamscan -".
--- /dev/null
+First, thanks again for making this plugin.
+
+I don't know if this is a problem for [[plugins/attachment]], but there seems to
+be no way to detect text/plain using File::MimeInfo::Magic::magic().
+There is a heuristic ::default that decides between text/plain and application/octet-stream.
+
+Would you be receptive to a patch that e.g. called File::MimeInfo::Magic::default()
+if ::magic() returns undef? --[[DavidBremner]]
+
+> Yes, that looks to be ok. --[[Joey]]
+
+>> OK, here is such a patch. One modification of previous behaviour is that
+>> that if default returns undef, this is returned. As far as I understand
+>> the code/doc for File::MimeInfo, under is used only as an error return
+>> for ::default
+
+>>> Applied
--- /dev/null
+[[!template id=plugin name=format core=0 author="[[Joey]]"]]
+[[!tag type/format]]
+
+This plugin allows mixing different page formats together, by embedding
+text formatted one way inside a page formatted another way. This is done
+using the [[ikiwiki/directive/format]] [[ikiwiki/directive]].
+
+For example, it could be used to embed an [[otl]] outline inside a page
+that is formatted as [[mdwn]].
--- /dev/null
+Is there any way to tell if an htmlize hook have been called from a format directive?
+
+I am currently modifying the [[contrib/highlightcode]] plugin by [[sabr]] and I wanted to have a different behavior depending on the fact that the htmlize hook is called from a format directive or not. For instance, this could disable the raw copy of the highlighted code. Since I have enabled the keepextension option, I tried to rely on the page extension to decide whenever I have to create the raw file or not but this does not seems a reliable approach.
+
+One possible solution is to add an optional parameter to the htmlize hook (and thus to htmlize function in IkiWiki.pm) which could tell if this is the format directive that called the function but I am not sure that is a good way to do this.
+
+> It's (probably) not just the format directive that has a potential problem here.
+> Imagine a syntax highlighted source code file that contains some other
+> directive, such as table or meta. Such a directive calls `htmlize` on the
+> parameters passed to it.
+>
+> There is one way to detect this ATM. If `%IkiWiki::preprocessing` has
+> anything in it, then ikiwiki is in the middle of handling a preprocessing
+> directive. So you could check that. It's getting into internals, so not
+> ideal.. --[[Joey]]
-[[template id=plugin name=fortune author="[[Joey]]"]]
-[[tag type/fun]]
+[[!template id=plugin name=fortune author="[[Joey]]"]]
+[[!tag type/fun]]
-This just uses the `fortune` program to insert a fortune into the page.
-Usage:
+This plugin implements the [[ikiwiki/directive/fortune]] [[ikiwiki/directive]].
+This directive uses the `fortune` program to insert a fortune into the page.
- \[[fortune ]]
-
-[[if test="enabled(fortune)" then="""
+[[!if test="enabled(fortune)" then="""
Here's a fortune for you:
----
-[[fortune ]]
+[[!fortune ]]
"""]]
--- /dev/null
+[[!template id=plugin name=getsource author="[[Will_Uther|Will]]"]]
+
+This plugin adds a "Source" link to the top of each page that uses
+the CGI to display the page's source.
+
+Configuration for this plugin in the setup file:
+
+* `getsource_mimetype => "text/plain; charset=utf-8"`
+
+ Sets the MIME type used when page source is requested. The default is
+ usually appropriate, but you could set this to `application/octet-stream`
+ to encourage browsers to download the source to a file rather than showing
+ it in the browser.
-[[template id=plugin name=goodstuff author="[[Joey]]"]]
-[[tag type/bundle]]
+[[!template id=plugin name=goodstuff author="[[Joey]]"]]
+[[!tag type/bundle]]
This plugin enables a bunch of other plugins -- basically all the ones that
are not too intrusive, work well with little configuration, and are nice to
* [[brokenlinks]]
* [[img]]
* [[map]]
-* [[meta]]
+* [[more]]
* [[orphans]]
* [[pagecount]]
* [[pagestats]]
+* [[progress]]
* [[shortcut]]
* [[smiley]]
* [[tag]]
+* [[table]]
* [[template]]
* [[toc]]
* [[toggle]]
-* [[otl]]
+* [[repolist]]
New plugins will be added to this bundle from time to time.
--- /dev/null
+[[!template id=plugin name=google author="Peter Simons"]]
+[[!tag type/web]]
+
+This plugin adds a search form to the wiki, using google's site search.
+
+Google is asked to search for pages in the domain specified in the wiki's
+`url` configuration parameter. Results will depend on whether google has
+indexed the site, and how recently. Also, if the same domain has other
+content, outside the wiki's content, it will be searched as well.
+
+The [[search]] plugin offers full text search of only the wiki, but
+requires that a search engine be installed on your site.
--- /dev/null
+This plugin uses the googleform.tmpl
+which produces valid HTML but invalid XHTML.
+This is not very good since the default ikiwiki
+templates produce XHTML instead of HTML.
+
+> Fixed, thanks for the patch! --[[Joey]]
+++ /dev/null
-[[template id=plugin name=googlecalendar author="[[Joey]]"]]
-[[tag type/special-purpose]]
-
-*Note*: This plugin is deprecated. Please switch to the [[embed]] plugin.
-
-This plugin allows embedding a google calendar iframe in the wiki.
-Normally, if the [[htmlscrubber]] is enabled, such iframes are scrubbed out
-of the wiki content since they're not very safe if created by malicious
-users. But some iframes are legitimate, and safe, if you trust the embedded
-content. This plugin is an example of how to deal with this in ikiwiki.
-
-Example use:
-
- \[[googlecalendar html="""
- <iframe src="http://www.google.com/calendar/embed?src=adkrdken8mupngh13jshlbenoc%40group.calendar.google.com&title=OSEL%20Calendar&chrome=NAVIGATION&bgcolor=%2371d873&height=588" style=" border-width:0 " width="480" frameborder="0" height="588"></iframe>
- """]]
-
-The iframe should be the one provided by google. Note that it's used in a
-way that avoids cross-site scripting attacks, assuming you trust google's
-content.
--- /dev/null
+[[!template id=plugin name=goto author="[[Simon_McVittie|smcv]]"]]
+[[!tag type/useful]]
+
+This plugin adds a `do=goto` mode for the IkiWiki CGI script. It's mainly
+for internal use by the [[404]], [[comments]] and [[recentchanges]]
+plugins, which enable it automatically.
+
+With this plugin enabled you can link to `ikiwiki.cgi?do=goto&page=some/where`
+to make a link that will redirect to the page `/some/where` if it exists, or
+offer a link to create it if it doesn't.
-[[template id=plugin name=graphviz author="[[JoshTriplett]]"]]
-[[tag type/chrome type/format]]
+[[!template id=plugin name=graphviz author="[[JoshTriplett]]"]]
+[[!tag type/chrome type/format]]
-This plugin allows embedding [graphviz](http://www.graphviz.org/) graphs in a
-page. Example usage:
-
- \[[graph src="a -> b -> c; a -> c;"]]
-
-Note that graphs will only show up in previews if your browser has
-[[wikipedia data: URI]] support, or if the same graph already exists on that
+This plugin provides the [[ikiwiki/directive/graph]] [[ikiwiki/directive]].
+This directive allows embedding [graphviz](http://www.graphviz.org/) graphs in a
page.
Security implications: graphviz does not seem to have any syntax exploitable to
allows for an amplification attack, since users can send less data to use large
amounts of processing time and disk usage.
-The `graph` directive supports the following parameters:
-
-- `src` - The graphviz source to render.
-- `type` - The type of graph to render: `graph` or `digraph`. Defaults to
- `digraph`.
-- `prog` - The graphviz program to render with: `dot`, `neato`, `fdp`, `twopi`,
- or `circo`. Defaults to `dot`.
-- `height`, `width` - Limit the size of the graph to a given height and width,
- in inches. You must specify both to limit the size; otherwise, graphviz will
- choose a size, without any limit.
-
-[[if test="enabled(graphviz)" then="""
+[[!if test="enabled(graphviz)" then="""
Some example graphs:
-[[graph src="a -> b -> c; a -> b;"]]
-[[graph src="a -- b -- c -- a;" prog="circo" type="graph"]]
+[[!graph src="a -> b -> c; a -> b;"]]
+[[!graph src="a -- b -- c -- a;" prog="circo" type="graph"]]
"""]]
-This plugin uses the [[cpan Digest::SHA1]] perl module.
+This plugin uses the [[!cpan Digest::SHA1]] perl module.
-[[template id=plugin name=haiku author="[[Joey]]"]]
-[[tag type/fun]]
+[[!template id=plugin name=haiku author="[[Joey]]"]]
+[[!tag type/fun]]
-This plugin allows inserting a randomly generated haiku into a wiki page.
-Just type:
-
- \[[haiku hint="argument"]]
-
-[[haiku hint="argument test"]]
-
-The hint parameter can be omitted, it only provides the generator a hint of
-what to write the haiku about. If no hint is given, it might base it on the
-page name. Since the vocabulary it knows is very small, many hints won't
-affect the result at all.
+This plugin provides a [[ikiwiki/directive/haiku]] [[ikiwiki/directive]].
+The directive allows inserting a randomly generated haiku into a wiki page.
As a special bonus, enabling this plugin makes any error messages ikiwiki
should display be written in haiku.
-You need to have the Coy module installed for this plugin to do anything
-interesting. That does all the heavy lifting.
+You need to have the [[!cpan Coy]] module installed for this plugin to do
+anything interesting. That does all the heavy lifting.
--- /dev/null
+[[!template id=plugin name=highlight author="[[Joey]]"]]
+[[!tag type/format]]
+
+This plugin allows ikiwiki to syntax highlight source code, using
+a fast syntax highlighter that supports over a hundred programming
+languages and file formats.
+
+## prerequisites
+
+You will need to install the perl bindings to the
+[highlight library](http://www.andre-simon.de/). In Debian
+they are in the [[!debpkg libhighlight-perl]] package. If
+your distribution does not have them, look in `examples/swig`
+in highlight's source.
+
+## embedding highlighted code
+
+To embed highlighted code on a page, you can use the
+[[format]] plugin.
+
+For example:
+
+ \[[!format c """
+ void main () {
+ printf("hello, world!");
+ }
+ """]]
+
+ \[[!format diff """
+ -bar
+ +foo
+ """]]
+
+You can do this for any extension or language name supported by
+the [highlight library](http://www.andre-simon.de/) -- basically anything
+you can think of should work.
+
+## highlighting entire source files
+
+To enable syntax highlighting of entire standalone source files, use the
+`tohighlight` setting in your setup file to control which files should be
+syntax highlighted. Here is a typical setting for it, enabling highlighting
+for files with the extensions .c, etc, and also for any files named
+"Makefile".
+
+ tohighlight => ".c .h .cpp .pl .py Makefile:make",
+
+It knows what language to use for most filename extensions (see
+`/etc/highlight/filetypes.conf` for a partial list), but if you want to
+bind an unusual filename extension, or any file without an extension
+(such as a Makefile), to a language, you can do so by appending a colon
+and the name of the language, as illustrated for Makefiles above.
+
+With the plugin configured this way, source files become full-fledged
+wiki pages, which means they can include [[WikiLinks|ikiwiki/wikilink]]
+and [[directives|ikiwiki/directive]] like any other page can, and are also
+affected by the [[smiley]] plugin, if it is enabled. This can be annoying
+if your code accidentially contains things that look like those.
+
+On the other hand, this also allows your syntax highlighed
+source code to contain markdown formatted comments and hyperlinks
+to other code files, like this:
+
+ /* \[[!format mdwn """
+ This comment will be formatted as *markdown*!
+
+ See \[[bar.h]].
+ ""]] */
+
+Finally, bear in mind that this lets anyone who can edit a page in your
+wiki also edit source code files that are in your wiki. Use appropriate
+caution.
+
+## colors
+
+The colors etc used for the syntax highlighting are entirely configurable
+by CSS. See ikiwiki's [[style.css]] for the defaults.
--- /dev/null
+It would be nice to be able to set a few options for the highlighter
+object. In particular, today I noticed my tabs were not being expanded
+correctly, which could be fixed the command line with --replace-tabs but
+programmatically needs a call to setPreformatting. I could probably play
+with this, but what is your preferred way to support options? something
+like 'highlight_options=>{replace_tabs=>8,line_numbers=>0}' ? Of course,
+if you want to implement it I won't complain :-). [[DavidBremner]]
+
+> I don't know about tab replacement, which I can't really see the point
+> of, but if there are multiple options, giving each its own nane would
+> word better for websetup than would putting all the options in a
+> sub-hash. --[[Joey]]
+
+
+Has anyone got this running with CentOS/RHEL ?
+Having trouble working out where to get the perl bindings for highlight. --[Mick](http://www.lunix.com.au)
+
+> The perl bindings are hidden in `examples/swig` in highlight's source.
+> --[[Joey]]
+
+Thanks for prompt reply.All working. I will post on my site tonight and link here what I did on CentOS to make this work. --[Mick](http://www.lunix.com.au)
-[[template id=plugin name=hnb author="[[XTaran]]"]]
-[[tag type/format type/slow]]
+[[!template id=plugin name=hnb author="[[XTaran]]"]]
+[[!tag type/format type/slow]]
This plugin allows ikiwiki to process `.hnb` XML files, as created by
the Hierachical Notebook [hnb](http://hnb.sourceforge.net/). To use it, you need to have
-[[template id=plugin name=html author="[[Joey]]"]]
-[[tag type/html type/format]]
+[[!template id=plugin name=html author="[[Joey]]"]]
+[[!tag type/html type/format]]
This plugin lets html pages be used as source pages for the wiki. The
html pages will still be wrapped in the same html template as any other
--- /dev/null
+[[!template id=plugin name=htmlbalance author="[[Simon_McVittie|smcv]]"]]
+[[!tag type/html]]
+
+This plugin ensures that the HTML emitted by ikiwiki contains well-balanced
+HTML tags, by parsing it with [[!cpan HTML::TreeBuilder]] and re-serializing it. This
+acts as a lighter-weight alternative to [[plugins/htmltidy]]; it doesn't
+ensure validity, but it does at least ensure that formatting from a
+blog post pulled in by the [[ikiwiki/directive/inline]] directive doesn't
+leak into the rest of the page.
--- /dev/null
+Would it be possible to use [[!cpan HTML::Entities]] rather than
+`XML::Atom::Util` for encoding entities? The former is already an ikiwiki
+dependency (via [[!cpan HTML::Parser]]).
+
+> Now switched to HTML::Entities --[[Joey]]
+
+I also wonder if there's any benefit to using this plugin aside from with
+aggregate. Perhaps a small one but aggregate seems like the main case..
+wondering if it would be better to just have aggregate balanace the html
+automatically and do away with the separate plugin. --[[Joey]]
-[[template id=plugin name=htmlscrubber core=1 author="[[Joey]]"]]
-[[tag type/html]]
+[[!template id=plugin name=htmlscrubber core=1 author="[[Joey]]"]]
+[[!tag type/html]]
This plugin is enabled by default. It sanitizes the html on pages it renders
to avoid XSS attacks and the like.
that the url is in a known, safe scheme, and to block embedded javascript
in such urls.
-It uses the [[cpan HTML::Scrubber]] perl module to perform its html
+It uses the [[!cpan HTML::Scrubber]] perl module to perform its html
sanitisation, and this perl module also deals with various entity encoding
tricks.
other HTML-related functionality, such as whether [[meta]] allows
potentially unsafe HTML tags.
+The `htmlscrubber_skip` configuration setting can be used to skip scrubbing
+of some pages. Set it to a [[ikiwiki/PageSpec]], such as "!*/Discussion",
+and pages matching that can have all the evil CSS, JavsScript, and unsafe
+html elements you like. One safe way to use this is to use [[lockedit]] to
+lock those pages, so only admins can edit them.
+
----
Some examples of embedded javascript that won't be let through when this
--- /dev/null
+**Ok, I have yet to post a big dummy wiki-noobie question around here, so here goes:**
+
+Yes, I want to play around with *gulp* Google Ads on an ikiwiki blog, namely, in the *sidebar*.
+
+No, I do not want to turn htmlscrubber off, but apart from that I have not been able to allow <script> elements as required by Google.
+
+Thoughts?
+
+---
+
+***Fixed!***
+
+Did some more reading, did some searching on the wiki, and found, under *embed*, these
+
+ htmlscrubber_skip => '!*/Discussion',
+ locked_pages => '!*/Discussion',
+
+Thanks!
-[[template id=plugin name=htmltidy author="Faidon Liambotis"]]
-[[tag type/html]]
-[[tag type/slow]]
+[[!template id=plugin name=htmltidy author="Faidon Liambotis"]]
+[[!tag type/html]]
+[[!tag type/slow]]
This plugin uses [tidy](http://tidy.sourceforge.net/) to tidy up the html
emitted by ikiwiki. Besides being nicely formatted, this helps ensure that
even if users enter suboptimal html, your wiki generates valid html.
Note that since tidy is an external program, that is run each time a page
-is built, this plugin will slow ikiwiki down somewhat.
+is built, this plugin will slow ikiwiki down somewhat. [[plugins/htmlbalance]]
+might provide a faster alternative.
-[[template id=plugin name=httpauth author="Alec Berryman"]]
-[[tag type/auth]]
+[[!template id=plugin name=httpauth author="Alec Berryman"]]
+[[!tag type/auth]]
This plugin allows HTTP basic authentication to be used to log into the
wiki. To use the plugin, your web server should be set up to perform HTTP
-basic authentiation. The authenticated user will be automatically signed
-into the wiki.
+basic authentiation for at least the directory containing `ikiwiki.cgi`.
+The authenticated user will be automatically signed into the wiki.
This plugin is included in ikiwiki, but is not enabled by default.
-[[template id=plugin name=img author="Christian Mock"]]
-[[tag type/chrome]]
+[[!template id=plugin name=img author="Christian Mock"]]
+[[!tag type/chrome]]
-This is an image handling plugin. While ikiwiki supports inlining full-size
-images by making a [[ikiwiki/WikiLink]] that points to the image, using
-this plugin you can easily scale down an image for inclusion onto a page,
-providing a link to a full-size version.
+This plugin provides the [[ikiwiki/directive/img]] [[ikiwiki/directive]].
+While ikiwiki supports inlining full-size images by making a
+[[ikiwiki/WikiLink]] that points to the image, using this directive you can
+easily scale down an image for inclusion onto a page, providing a link to a
+full-size version.
This plugin uses the [ImageMagick](http://www.imagemagick.org/) tools via
[PerlMagick](http://www.imagemagick.org/www/perl-magick.html).
Note that this is a stripped down version of Christian Mock's
[[original_img_plugin|contrib/img]].
-
-## usage
-
- \[[img image1.jpg size="200x200" alt="clouds"]]
-
-The image file will be searched for using the same rules as used to find
-the file pointed to by a [[ikiwiki/WikiLink]].
-
-The `size` parameter is optional, defaulting to full size. Note that the
-original image's aspect ratio is always preserved, even if this means
-making the image smaller than the specified size.
-
-You can also pass `alt`, `title`, `class` and `id` parameters. These are
-passed through unchanged to the html img tag. If you include a `caption`
-parameter, the caption will be displayed centered beneath the image.
-
-The `link` parameter is used to control whether the scaled down image links
-to the full size version. By default it does; set "link=somepage" to link
-to another page instead, or "link=no" to disable the link, or
-"link=http://url" to link to a given url.
-
-You can also set default values that will be applied to all later images on
-the page, unless overridden. Useful when including many images on a page.
-
- \[[img defaults size=200x200 alt="wedding photo"]]
- \[[img photo1.jpg]]
- \[[img photo2.jpg]]
- \[[img photo3.jpg size=200x600]]
instead of linking to the PNG image file. --[[tschwinge]]
> Done, use link=somepage --[[Joey]]
+
+It would be handy if the `class` and `id` tags were passed through to the surrounding `table` in the case of `caption` being present. Would this break anything? --[[neale]]
+
+> Seems unlikely to break *too* much. I can imagine css that styles the img
+> unexpectedly applying the table. --[[Joey]]
-[[template id=plugin name=inline core=1 author="[[Joey]]"]]
-
-This is a [[ikiwiki/PreProcessorDirective]] that allows including one wiki page
-inside another. For example:
-
- \[[inline pages="blog/*"]]
-
-The most common use of inlining is generating blogs and RSS or Atom feeds.
-See [[ikiwiki/blog]] for details.
+[[!template id=plugin name=inline core=1 author="[[Joey]]"]]
+This plugin provides the [[ikiwiki/directive/inline]]
+[[ikiwiki/directive]], which allows including one wiki page
+inside another.
-[[meta title="Installing third party plugins"]]
+[[!meta title="Installing third party plugins"]]
Most ikiwiki plugins are perl modules and should be installed somewhere in
the perl module search path. See the @INC list at the end of the output of
-[[template id=plugin name=link core=1 author="[[Joey]]"]]
-[[tag type/link]]
+[[!template id=plugin name=link core=1 author="[[Joey]]"]]
+[[!tag type/link]]
-This plugin implements standard [[WikiLinks|WikiLink]].
+This plugin implements standard [[WikiLinks|ikiwiki/wikilink]].
-[[template id=plugin name=linkmap author="[[Joey]]"]]
-[[tag type/meta]]
-[[tag type/slow]]
-This plugin uses [graphviz](http://www.graphviz.org/) to generate a graph showing the links between a
-set of pages in the wiki. Example usage:
+[[!template id=plugin name=linkmap author="[[Joey]]"]]
+[[!tag type/meta]]
+[[!tag type/slow]]
- \[[linkmap pages="* and !blog/* and !*/Discussion"]]
+This plugin provides the [[ikiwiki/directive/linkmap]] [[ikiwiki/directive]].
+It uses [graphviz](http://www.graphviz.org/) to generate a graph showing the
+links between a set of pages in the wiki.
-Only links between mapped pages will be shown; links pointing to or from
-unmapped pages will be omitted. If the pages to include are not specified,
-the links between all pages (and other files) in the wiki are mapped. For
-best results, only a small set of pages should be mapped, since otherwise
-the map can become very large, unweildy, and complicated. Also, the map is
-rebuilt whenever one of the mapped pages is changed, which can make the
-wiki a bit slow.
-
-Here are descriptions of all the supported parameters to the `linkmap`
-directive:
-
-* `pages` - A [[ikiwiki/PageSpec]] of the pages to map.
-* `height`, `width` - Limit the size of the map to a given height and width,
- in inches. Both must be specified for the limiting to take effect, otherwise
- the map's size is not limited.
-
-[[if test="enabled(linkmap)" then="""
+[[!if test="enabled(linkmap)" then="""
Here is an example link map, of the index page and all pages it links to:
-[[linkmap pages="index or (backlink(index) and !*.png)"]]
+[[!linkmap pages="index or (backlink(index) and !*.png)"]]
"""]]
--- /dev/null
+[[!template id=plugin name=listdirectives author="Will"]]
+[[!tag type/meta]]
+
+This plugin provides the [[ikiwiki/directive/listdirectives]]
+[[ikiwiki/directive]], which inserts a list of currently available
+directives into the page.
+
+Each directive links to a wiki page with the same name, that should
+document that directive. The location of these pages can be controlled via
+the `directive_description_dir` setting in the setup file, the default is
+"ikiwiki/directive/foo".
+
+When this plugin is enabled, it enables the directives underlay, which
+contains documentation about all the directives included in plugins shipped
+with ikiwiki. This adds about 200 kb to the size of your wiki.
-[[template id=plugin name=lockedit core=1 author="[[Joey]]"]]
-[[tag type/auth]]
+[[!template id=plugin name=lockedit core=1 author="[[Joey]]"]]
+[[!tag type/auth]]
-This plugin enables [[page_locking]]. It is enabled by default.
+This plugin allows the administrator of a wiki to lock some pages, limiting
+who can edit them using the online interface. This doesn't prevent anyone
+who can commit to the underlying revision control system from editing the
+pages, however. (Unless you set up [[tips/untrusted_git_push]].)
+
+The `locked_pages` setting configures what pages are locked. It is a
+[[ikiwiki/PageSpec]], so you have lots of control over what kind of pages
+to lock. For example, you could choose to lock all pages created before
+2006, or all pages that are linked to from the page named "locked". More
+usually though, you'll just list some names of pages to lock.
+
+One handy thing to do if you're using ikiwiki for your blog is to lock
+"* and !*/Discussion". This prevents others from adding to or modifying
+posts in your blog, while still letting them comment via the Discussion
+pages.
+
+Alternatively, if you're using the [[comments]] plugin, you can lock
+"!postcomment(*)" to allow users to comment on pages, but not edit anything
+else.
+
+Wiki administrators can always edit locked pages. The [[ikiwiki/PageSpec]]
+can specify that some pages are not locked for some users. For example,
+"important_page and !user(joey)" locks `important_page` while still
+allowing joey to edit it, while "!*/Discussion and user(bob)" prevents bob
+from editing pages except for Discussion pages.
-[[template id=plugin name=map author="Alessandro Dotti Contra"]]
-[[tag type/meta]]
+[[!template id=plugin name=map author="Alessandro Dotti Contra"]]
+[[!tag type/meta]]
-[[meta description="some page description"]]
+This plugin provides the [[ikiwiki/directive/map]] [[ikiwiki/directive]],
+which generates a hierarchical page map for the wiki.
-This plugin generates a hierarchical page map for the wiki. Example usage:
-
- \[[map pages="* and !blog/* and !*/Discussion"]]
-
-If the pages to include are not specified, all pages (and other files) in
-the wiki are mapped.
-
-By default, the names of pages are shown in the map. The `show` parameter
-can be used to show the titles or descriptions of pages instead (as set by
-the [[meta]] plugin). For example:
-
- \[[map pages="* and !blog/* and !*/Discussion" show=title]]
-
-Hint: To limit the map to displaying pages less than a certain level deep,
-use a [[ikiwiki/PageSpec]] like this: `pages="* and !*/*/*"`
-
-[[if test="enabled(map)" then="""
+[[!if test="enabled(map)" then="""
Here's an example map, for the plugins section of this wiki:
-[[map pages="(plugins or plugins/*) and !*/*/*"]]
+[[!map pages="(plugins or plugins/*) and !*/*/*"]]
"""]]
We'd also very much like to have an option to display the title of the page instead of the filename in the map plugin. --Andrew
-There's a patch implementing this in [[debbug 484510]]. It needs a few fixes
+There's a patch implementing this in [[!debbug 484510]]. It needs a few fixes
before I merge it. Now applied. --[[Joey]]
+
+----
+
+I noticed that when the pagespec returns no map items, the map plugin does not close off the ul and div tags. Below is a simple patch
+that seems to work on the examples I tried. I am a beginner so please help me out here. Thanks. --[[harishcm]]
+
+ --- a/map.pm
+ +++ b/map.pm
+ @@ -81,6 +81,13 @@
+ my $openli=0;
+ my $addparent="";
+ my $map = "<div class='map'>\n<ul>\n";
+ +
+ + # Return properly closed $map if %mapitems is empty
+ + if (!scalar(keys %mapitems)) {
+ + $map .= "</ul>\n</div>\n";
+ + return $map;
+ + }
+ +
+ foreach my $item (sort keys %mapitems) {
+ my @linktext = (length $mapitems{$item} ? (linktext => $mapitems{$item}) : ());
+ $item=~s/^\Q$common_prefix\E\///
+
+> This was also reported as [[bugs/map_fails_to_close_ul_element_for_empty_list]];
+> this patch is simpler than the one there, but has the same problem (it emits
+> `<ul></ul>`, which technically isn't valid HTML either). --[[smcv]]
+
+>> Thanks for the tip, I added another patch addressing the issue at
+>> [[bugs/map_fails_to_close_ul_element_for_empty_list]]. --[[harishcm]]
-[[template id=plugin name=mdwn core=1 author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=mdwn core=1 author="[[Joey]]"]]
+[[!tag type/format]]
This plugin lets ikwiki convert files with names ending in ".mdwn" to html.
It uses the [[ikiwiki/markdown]] minimal markup language.
There are several implementations of markdown support that can be used by
this plugin. The [original version of
markdown](http://daringfireball.net/projects/markdown/) can be used, or the
-[[cpan Text::Markdown]] perl module.
+[[!cpan Text::Markdown]] perl module.
-[[cpan Text::Markdown]] also includes a markdown variant called
+[[!cpan Text::Markdown]] also includes a markdown variant called
[multimarkdown](http://fletcherpenney.net/MultiMarkdown/), which supports
tables, footnotes, and other new features. Multimarkdown is not enabled by
default, but can be turned on via the `multimarkdown` option in the setup
--- /dev/null
+Unlike other format, ikiwiki is somehow depends
+on mdwn, since the underlay dir
+is written in mdwn. If you want to disable mdwn,
+you need to overwrite the underlay
+dir (set underlaydir in ikiwiki.setup
+to your own underlay dir or replace underlay pages
+in your $SRC).
-[[template id=plugin name=meta author="[[Joey]]"]]
-[[tag type/meta]]
+[[!template id=plugin name=meta core=1 author="[[Joey]]"]]
+[[!tag type/meta]]
-This plugin allows inserting arbitrary metadata into the source of a page.
-Enter the metadata as follows:
-
- \[[!meta field="value"]]
- \[[!meta field="value" param="value" param="value"]]
-
-The first form sets a given field to a given value, while the second form
-also specifies some additional sub-parameters.
-
-The field values are treated as HTML entity-escaped text, so you can include
-a quote in the text by writing `"` and so on.
-
-Supported fields:
-
-* title
-
- Overrides the title of the page, which is generally the same as the
- page name.
-
- Note that if the title is overridden, a "title_overridden" variable will
- be set to a true value in the template; this can be used to format things
- differently in this case.
-
-* license
-
- Specifies a license for the page, for example, "GPL". Can contain
- WikiLinks and arbitrary markup.
-
-* copyright
-
- Specifies the copyright of the page, for example, "Copyright 2007 by
- Joey Hess". Can contain WikiLinks and arbitrary markup.
-
-* author
-
- Specifies the author of a page.
-
-* authorurl
-
- Specifies an url for the author of a page.
-
-* permalink
-
- Specifies a permanent link to the page, if different than the page
- generated by ikiwiki.
-
-* date
-
- Specifies the creation date of the page. The date can be entered in
- nearly any format, since it's parsed by [[cpan TimeDate]].
-
-* stylesheet
-
- Adds a stylesheet to a page. The stylesheet is treated as a wiki link to
- a `.css` file in the wiki, so it cannot be used to add links to external
- stylesheets. Example:
-
- \[[!meta stylesheet=somestyle rel="alternate stylesheet"
- title="somestyle"]]
-
-* openid
-
- Adds html <link> tags to perform OpenID delegation to an external
- OpenID server (for `openid` and `openid2`). An optional `xrds-location`
- parameter lets you specify the location of any [eXtensible Resource
- DescriptorS](http://www.windley.com/archives/2007/05/using_xrds.shtml).
-
- This lets you use an ikiwiki page as your OpenID. Example:
-
- \\[[!meta openid="http://joeyh.myopenid.com/"
- server="http://www.myopenid.com/server"
- xrds-location="http://www.myopenid.com/xrds?username=joeyh.myopenid.com""]]
-
-* link
-
- Specifies a link to another page. This can be used as a way to make the
- wiki treat one page as linking to another without displaying a user-visible
- [[ikiwiki/WikiLink]]:
-
- \[[!meta link=otherpage]]
-
- It can also be used to insert a html <link> tag. For example:
-
- \[[!meta link="http://joeyh.myopenid.com/" rel="openid.delegate"]]
-
- However, this latter syntax won't be allowed if the [[htmlscrubber]] is
- enabled, since it can be used to insert unsafe content.
-
-* redir
-
- Causes the page to redirect to another page in the wiki.
-
- \[[!meta redir=otherpage]]
-
- Optionally, a delay (in seconds) can be specified. The default is to
- redirect without delay.
-
- It can also be used to redirect to an external url. For example:
-
- \[[!meta redir="http://example.com/"]]
-
- However, this latter syntax won't be allowed if the [[htmlscrubber]] is
- enabled, since it can be used to insert unsafe content.
-
- For both cases, an anchor to jump to inside the destination page may also be
- specified using the common `PAGE#ANCHOR` syntax.
-
-* robots
-
- Causes the robots meta tag to be written:
-
- \[[!meta robots="index, nofollow"]]
-
- Valid values for the attribute are: "index", "noindex", "follow", and
- "nofollow". Multiple comma-separated values are allowed, but obviously only
- some combinations make sense. If there is no robots meta tag, "index,
- follow" is used as the default.
-
- The plugin escapes the value, but otherwise does not care about its
- contents. In particular, it does not check the values against the set of
- valid values but serves whatever you pass it.
-
-If the field is not one of the above predefined fields, the metadata will be
-written to the generated html page as a <meta> header. However, this
-won't be allowed if the [[htmlscrubber]] is enabled, since it can be used to
-insert unsafe content.
+This plugin provides the [[ikiwiki/directive/meta]] [[ikiwiki/directive]],
+which allows inserting various metadata into the source of a page.
--[[Paweł|ptecza]]
-> As with any other parameter in a [[ikiwiki/preprocessordirective]], you can
+> As with any other parameter in a [[ikiwiki/directive]], you can
> triple-quote, and then include quotation marks inside. --[[Joey]]
>> Thanks for the hint! Toggle plugin is probably my favourite ikiwiki
-[[template id=plugin name=mirror author="[[Joey]]"]]
-[[tag type/special-purpose]]
+[[!template id=plugin name=mirror author="[[Joey]]"]]
+[[!tag type/special-purpose]]
This plugin allows adding links a list of mirrors to each page in the
wiki. For each mirror, a name and an url should be specified. Pages are
assumed to exist in the same location under the specified url on each
-mirror. The [[ikiwiki.setup]] file has an example of configuring a list of
-mirrors.
+mirror.
-[[template id=plugin name=more author="Ben"]]
-[[tag type/format]]
+[[!template id=plugin name=more author="Ben"]]
+[[!tag type/format]]
-This plugin provides a way to have a "more" link on a page in a blog, that
-leads to the full version of the page. Use it like this:
-
- \[[more linktext="click for more" text="""
- This is the rest of my post. Not intended for people catching up on
- their blogs at 30,000 feet. Because I like to make things
- difficult.
- """]]
-
-If the `linktext` parameter is omitted it defaults to just "more".
-
-Note that you can accomplish something similar using a [[toggle]] instead.
+This plugin provides the [[ikiwiki/directive/more]] [[ikiwiki/directive]],
+which is a way to have a "more" link on a post in a blog, that leads to the
+full version of the page.
--- /dev/null
+# Test:
+
+[[!more linktext="click for more" text="""
+This is the rest of my post. Not intended for people catching up on
+their blogs at 30,000 feet. Because I like to make things
+difficult.
+"""]]
-[[template id=plugin name=opendiscussion author="[[Joey]]"]]
-[[tag type/auth]]
+[[!template id=plugin name=opendiscussion author="[[Joey]]"]]
+[[!tag type/auth]]
This plugin allows editing of Discussion pages by anonymous users who have
not logged into the wiki.
-[[template id=plugin name=openid core=1 author="[[Joey]]"]]
-[[tag type/auth]]
+[[!template id=plugin name=openid core=1 author="[[Joey]]"]]
+[[!tag type/auth]]
This plugin allows users to use their [OpenID](http://openid.net/) to log
into the wiki.
-The plugin needs the [[cpan Net::OpenID::Consumer]] perl module. The
-[[cpan LWPx::ParanoidAgent]] perl module is used if available, for added
-security. Finally, the [[cpan Crypt::SSLeay]] perl module is needed to support
-users entering "https" OpenID urls.
+The plugin needs the [[!cpan Net::OpenID::Consumer]] perl module.
+Version 1.x is needed in order for OpenID v2 to work.
+
+The [[!cpan LWPx::ParanoidAgent]] perl module is used if available, for
+added security. Finally, the [[!cpan Crypt::SSLeay]] perl module is needed
+to support users entering "https" OpenID urls.
This plugin has a configuration option. You can set `--openidsignup`
to the url of a third-party site where users can sign up for an OpenID. If
See <http://umeet.uninet.edu/umeet2007/english/prog.html> for the complete program
and for information about how to join.
---[[tschwinge]]
\ No newline at end of file
+--[[tschwinge]]
+
+----
+<a id="Yahoo_unsupported" />
+[[!tag bugs]]
+
+It looks like OpenID 2.0 (the only supported by Yahoo) is not supported in ikiwiki. :( I signed up at http://openid.yahoo.com/ , and tried to login to my ikiwiki with the new ID (of the form: https://me.yahoo.com/a-username), but Yahoo told me:
+
+> Sorry! You will not be able to login to this website as it is using an older version of the the OpenID technology. Yahoo! only supports OpenID 2.0 because it is more secure. For more information, check out the OpenID documentation at [Yahoo! Developer Network](http://developer.yahoo.com/openid/).
+
+-- Ivan Z.
+
+They have more on OpenID 2.0 in [their FAQ](http://developer.yahoo.com/openid/faq.html). --Ivan Z.
-[[template id=plugin name=orphans author="[[Joey]]"]]
-[[tag type/meta]]
+[[!template id=plugin name=orphans author="[[Joey]]"]]
+[[!tag type/meta]]
-This plugin generates a list of possibly orphaned pages -- pages that no
-other page links to.
+This plugin provides the [[ikiwiki/directive/orphans]]
+[[ikiwiki/directive]], which generates a list of possibly orphaned pages --
+pages that no other page links to.
-The optional parameter "pages" can be a [[ikiwiki/PageSpec]] specifying the
-pages to check for orphans, default is search them all.
-
-Note that it takes [[BackLinks]] into account, but does not count inlining a
-page as linking to it, so will generally count many blog-type pages as
-orphans.
-
-[[if test="enabled(orphans)" then="""
+[[!if test="enabled(orphans)" then="""
Here's a list of orphaned pages on this wiki:
-[[orphans pages="* and !news/* and !todo/* and !bugs/* and !users/* and
+[[!orphans pages="* and !news/* and !todo/* and !bugs/* and !users/* and
!recentchanges and !examples/* and !tips/* and !sandbox/* and !templates/* and
!wikiicons/* and !plugins/*"]]
"""]]
--- /dev/null
+It seems that the orphans plugin doesn't recognize markdown-style links of the kind:
+
+ [Pretty link name](realname)
+
+In my wiki, the page "realname" shows up as an orphan although it's being linked to.
+
+> Like anything in ikiwiki that deals with links, this only takes
+> [[WikiLinks|ikiwiki/wikilink]] into account. There should be no real
+> reason to use other link mechanisms provided by eg, markdown for internal
+> links in the wiki (indeed, using them is likely to cause broken links
+> when doing things like inlining or renaming pages). --[[Joey]]
+
+
+The orphans plugin fails with an error when it has to deal with a page that contains '+' characters as part of the filename. Apparently the code uses regular expressions and forgets to quote that string at some cruicial point. The error message I see is:
+
+ \[[!orphans Error: Nested quantifiers in regex;
+ marked by <-- HERE in m/^(c++ <-- HERE |)$/ at
+ /usr/lib/perl5/vendor_perl/5.8.8/IkiWiki/Plugin/orphans.pm line 43.]]
+
+--Peter
+
+> Fixed. BTW, for an important bug like this, use [[bugs]]. --[[Joey]]
-[[template id=plugin name=otl author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=otl author="[[Joey]]"]]
+[[!tag type/format]]
This plugin allows ikiwiki to process `.otl` outline files, as created by
[vimoutliner](http://www.vimoutliner.org/). To use it, you need to have
-[[template id=plugin name=pagecount author="[[Joey]]"]]
-[[tag type/meta]]
+[[!template id=plugin name=pagecount author="[[Joey]]"]]
+[[!tag type/meta]]
-Provides a \\[[pagecount ]] [[ikiwiki/PreProcessorDirective]] that is
-replaced with the total number of pages currently in the wiki.
-
-The optional parameter "pages" can be a [[ikiwiki/PageSpec]] specifying the
-pages to count, default is to count them all.
-
-This plugin is included in ikiwiki, but is not enabled by default.
+This plugin provides the [[ikiwiki/directive/pagecount]]
+[[ikiwiki/directive]], which displays the number of pages
+currently in the wiki.
If it is turned on it can tell us that this wiki includes
-[[pagecount pages="* and !recentchanges"]]
-pages, of which [[pagecount pages="*/Discussion"]] are discussion pages.
+[[!pagecount ]] pages, of which
+[[!pagecount pages="*/Discussion"]] are discussion pages.
-[[template id=plugin name=pagestats author="Enrico Zini"]]
-[[tag type/meta type/tags]]
+[[!template id=plugin name=pagestats author="Enrico Zini"]]
+[[!tag type/meta type/tags]]
-This plugin can generate stats about how pages link to each other. It can
-produce either a del.icio.us style cloud, or a table counting the number of
-links to each page.
-
-Here's how to use it to create a [[tag]] cloud:
-
- \[[pagestats pages="tags/*"]]
-
-And here's how to create a table of all the pages on the wiki:
-
- \[[pagestats style="table"]]
+This plugin provides the [[ikiwiki/directive/pagestats]]
+[[ikiwiki/directive]], which can generate stats about how pages link to
+each other, or display a tag cloud.
-[[template id=plugin name=pagetemplate author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=pagetemplate author="[[Joey]]"]]
+[[!tag type/chrome]]
-This plugin allows a page to be created using a different
-[[template|wikitemplates]]. The page text is inserted into the template, so
-the template controls the overall look and feel of the wiki page. This is
-in contrast to the [[template]] plugin, which allows inserting templates
-_into_ the body of a page.
+This plugin provides the [[ikiwiki/directive/pagetemplate]]
+[[ikiwiki/directive]], which allows a page to be created using a different
+[[template|wikitemplates]].
This plugin can only use templates that are already installed in
-/usr/share/ikiwiki/templates (or wherever ikiwiki is configured to look for
-them). You can choose to use any .tmpl files in that directory. Example:
-
- \[[pagetemplate template=my_fancy.tmpl]]
+`/usr/share/ikiwiki/templates` (or wherever ikiwiki is configured to look for
+them). You can choose to use any .tmpl files in that directory.
--- /dev/null
+[[!template id=plugin name=parentlinks core=1 author="[[intrigeri]]"]]
+[[!tag type/link]]
+
+This plugin generates the links to a page's parents that typically appear
+at the top of a wiki page.
-[[template id=plugin name=passwordauth core=1 author="[[Joey]]"]]
-[[tag type/auth]]
+[[!template id=plugin name=passwordauth core=1 author="[[Joey]]"]]
+[[!tag type/auth]]
This plugin lets ikiwiki prompt for a user name and password when logging
into the wiki. It also handles registering users, resetting passwords, and
Users' passwords are stored in the `.ikiwiki/userdb` file, which needs to
be kept safe to prevent exposure of passwords. If the
-[[cpan Authen::Passphrase]] perl module is installed, only hashes of the
+[[!cpan Authen::Passphrase]] perl module is installed, only hashes of the
passwords will be stored. This is strongly recommended.
The `password_cost` configuration option can be used to make the stored
>> Aha, then the problem is Firefox, which is automatically filling the
>> *Password* field with its previous value, but not filling the
>> *Confirm Password* one. --[[tschwinge]]
+
+## easy access to the userdb for apache auth?
+
+My use case is:
+
+* restricted ikiwiki
+* read/edit only allowed from the local network (done with apache restrictions)
+* edit only for people authenticated (done with vanilla ikiwiki passwordauth)
+
+I would like to allow people to read/edit the wiki from outside of the
+local network, if and only if they already have an ikiwiki account.
+
+[[httpauth]] doesn't fit since it doesn't allow anonymous local users
+to create their own account. I want a single, local, simple auth
+database.
+
+My (naïve?) idea would be:
+
+* keep the [[passwordauth]] system
+* provide a way for Apache to use the userdb for authentication if
+people want to connect from outside
+
+I looked at the various auth modules for apache2. It seems that none
+can use a "perl Storable data" file. So, I think some solutions could
+be:
+
+* use a sqlite database instead of a perl Storable file
+ * can be used with
+ [mod_auth_dbd](http://httpd.apache.org/docs/2.2/mod/mod_authn_dbd.html)
+ * requires a change in ikiwiki module [[passwordauth]]
+* use an external program to read the userdb and talk with
+ [mod_auth_external](http://unixpapa.com/mod_auth_external.html)
+ * requires the maintainance of this external auth proxy over ikiwiki
+ userdb format changes
+ * (I don't know perl)
+* include this wrapper in ikiwiki
+ * something like `ikiwiki --auth user:pass:userdb` check the
+ `user:pass` pair in `userdb` and returns an Accept/Reject flag to
+ Apache
+ * requires a change in ikiwiki core
+ * still requires
+ [mod_auth_external](http://unixpapa.com/mod_auth_external.html)
+* do it with Apache perl sections
+ * (I don't know perl)
+
+Any opinion/suggestion/solution to this is welcome and appreciated.
+
+--
+[[NicolasLimare]]
+
+For a similar use case, I've been intending to implement
+[[todo/httpauth_feature_parity_with_passwordauth]], but your idea may
+actually be the way to go. IMHO, the Perl sections idea is the
+easiest to setup, but on the long run, I'd prefer ikiwiki to optionnally
+use a userdb storage backend supported at least by Apache and lighttpd.
+--[[intrigeri]]
+
+Tons of CPAN modules may help, but most of them are specific to `mod_perl`,
+and AFAIK, ikiwiki is generally not run with `mod_perl`. It's not clear to me
+wether these modules depend on the webapp to be run with `mod_perl` set
+as the script handler, or only on `mod_perl` to be installed and loaded.
+
+* CPAN's `Apache::AuthenHook` allows to plug arbitrary Perl handlers as
+ Apache authentication providers.
+* CPAN's `Apache::Authen::Program` (`mod_perl`)
+* [http://www.openfusion.com.au/labs/mod_auth_tkt/](mod_auth_tkt) along with CPAN's
+ `Apache::AuthTkt`
+--[[intrigeri]]
+
+I've more or less managed to implement something based on `mod_perl` and
+`Apache::AuthenHook`, respectively in Debian packages `libapache2-mod-perl2`
+and `libapache-authenhook-perl`.
+
+In the Apache VirtualHost configuration, I have added the following:
+
+ PerlLoadModule Apache::AuthenHook
+ PerlModule My::IkiWikiBasicProvider
+
+ <Location /test/>
+ AuthType Basic
+ AuthName "wiki"
+ AuthBasicProvider My::IkiWikiBasicProvider
+ Require valid-user
+ ErrorDocument 401 /test/ikiwiki.cgi?do=signin
+ </Location>
+ <LocationMatch "^/test/(ikiwiki\.cgi$|.*\.css$|wikiicons/)">
+ Satisfy any
+ </LocationMatch>
+
+The perl module lies in `/etc/apache2/My/IkiWikiBasicProvider.pm`:
+
+ package My::IkiWikiBasicProvider;
+
+ use warnings;
+ use strict;
+ use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED);
+ use Storable;
+ use Authen::Passphrase;
+
+ sub userinfo_retrieve () {
+ my $userinfo=eval{ Storable::lock_retrieve("/var/lib/ikiwiki/test/.ikiwiki/userdb") };
+ return $userinfo;
+ }
+
+ sub handler {
+ my ($r, $user, $password) = @_;
+ my $field = "password";
+
+ if (! defined $password || ! length $password) {
+ return Apache2::Const::DECLINED;
+ }
+ my $userinfo = userinfo_retrieve();
+ if (! length $user || ! defined $userinfo ||
+ ! exists $userinfo->{$user} || ! ref $userinfo->{$user}) {
+ return Apache2::Const::DECLINED;
+ }
+ my $ret=0;
+ if (exists $userinfo->{$user}->{"crypt".$field}) {
+ error $@ if $@;
+ my $p = Authen::Passphrase->from_crypt($userinfo->{$user}->{"crypt".$field});
+ $ret=$p->match($password);
+ }
+ elsif (exists $userinfo->{$user}->{$field}) {
+ $ret=$password eq $userinfo->{$user}->{$field};
+ }
+ if ($ret) {
+ return Apache2::Const::OK;
+ }
+ return Apache2::Const::DECLINED;
+ }
+
+ 1;
+
+This setup also allows people with the master password to create their own
+account.
+
+I'm not really fluent in Perl, and all this can probably be improved (*or
+might destroy your computer as it is* and YMMV).
+
+-- [[Lunar]]
-[[template id=plugin name=pingee author="[[Joey]]"]]
-[[tag type/special-purpose]]
+[[!template id=plugin name=pingee author="[[Joey]]"]]
+[[!tag type/special-purpose]]
This plugin causes ikiwiki to listen for pings, typically delivered from
another ikiwiki instance using the [[pinger]] plugin. When a ping is
-recieved, ikiwiki will update the wiki, the same as if `ikiwiki --refresh`
+received, ikiwiki will update the wiki, the same as if `ikiwiki --refresh`
were ran at the command line.
An url such as the following is used to trigger a ping:
-[[template id=plugin name=pinger author="[[Joey]]"]]
-[[tag type/special-purpose]]
+[[!template id=plugin name=pinger author="[[Joey]]"]]
+[[!tag type/special-purpose]]
This plugin allows ikiwiki to be configured to hit a URL each time it
updates the wiki. One way to use this is in conjunction with the [[pingee]]
a wiki. By pinging the mirror or branch each time the main wiki changes, it
can be kept up-to-date.
- \[[!ping from="http://mywiki.com/"
- to="http://otherwiki.com/ikiwiki.cgi?do=ping"]]
+To configure what URLs to ping, use the [[ikiwiki/directive/ping]]
+[[ikiwiki/directive]].
-The "from" parameter must be identical to the url of the wiki that is doing
-the pinging. This is used to prevent ping loops.
-
-The "to" parameter is the url to ping. The example shows how to ping
-another ikiwiki instance.
-
-The [[cpan LWP]] perl module is used for pinging. Or the [[cpan
+The [[!cpan LWP]] perl module is used for pinging. Or the [[!cpan
LWPx::ParanoidAgent]] perl module is used if available, for added security.
-Finally, the [[cpan Crypt::SSLeay]] perl module is needed to support pinging
+Finally, the [[!cpan Crypt::SSLeay]] perl module is needed to support pinging
"https" urls.
By default the pinger will try to ping a site for 15 seconds before timing
+++ /dev/null
-I guess the reason I never thought to write this is when I put a .txt file
-in ikiwiki, I'm happy enough to see it copied through unchanged.
-
-I guess the advantage of using this plugin is that you get the page wrapper
-around the preformatted text, and could even inline such a page.
-
-There is not currently a good way to turn off some processing steps for
-some page types. It's either all or nothing. The patch in
-[[todo/format_escape]] might allow a formatter to register its own special
-version of htmllink that didn't do anything, but would that be enough?
-
---[[Joey]]
-
-[Here](http://www.gmcmanus.org/plaintext.pm) is an alternate approach.
-It encodes entities using a filter hook, before wikilinks are linkified.
-So wikilinks turn up as links.
-It also uses URI::Find to turn URIs into links.
-
-I'm not very familiar with Perl, so this code could be improved.
-
---Gabriel
-
-I like this approach! It sidesteps the annoying problem, and it actually
-makes the .txt format genuinely wiki-like, by allowing wikilinks and
-preprocessor directices.
-
-The only thing I am not sure about is the conversion of external urls to
-hyperlinks.
-
-Can you please add a copyright/license statemnt to the top of the plugin?
-If you do, I'll add it to ikiwiki. Thanks! --[[Joey]]
-
-> I've added copyright and license (GPLv2 or later). --Gabriel
--- /dev/null
+[[!template id=plugin name=po core=0 author="[[intrigeri]]"]]
+[[!tag type/format]]
+
+This plugin adds support for multi-lingual wikis, translated with
+gettext, using [po4a](http://po4a.alioth.debian.org/).
+
+It depends on the Perl `Locale::Po4a::Po` library (`apt-get install po4a`).
+As detailed bellow in the security section, `po4a` is subject to
+denial-of-service attacks before version 0.35.
+
+[[!toc levels=2]]
+
+Introduction
+============
+
+A language is chosen as the "master" one, and any other supported
+language is a "slave" one.
+
+A page written in the "master" language is a "master" page. It can be
+of any page type supported by ikiwiki, except `po`. It does not have to be
+named a special way: migration to this plugin does not imply any page
+renaming work.
+
+Example: `bla/page.mdwn` is a "master" Markdown page written in
+English; if `usedirs` is enabled, it is rendered as
+`bla/page/index.en.html`, else as `bla/page.en.html`.
+
+Any translation of a "master" page into a "slave" language is called
+a "slave" page; it is written in the gettext PO format. `po` is now
+a page type supported by ikiwiki.
+
+Example: `bla/page.fr.po` is the PO "message catalog" used to
+translate `bla/page.mdwn` into French; if `usedirs` is enabled, it is
+rendered as `bla/page/index.fr.html`, else as `bla/page.fr.html`
+
+(In)Compatibility
+=================
+
+This plugin does not support the `indexpages` mode. If you don't know
+what it is, you probably don't care.
+
+
+Configuration
+=============
+
+Supported languages
+-------------------
+
+`po_master_language` is used to set the "master" language in
+`ikiwiki.setup`, such as:
+
+ po_master_language => { 'code' => 'en', 'name' => 'English' }
+
+`po_slave_languages` is used to set the list of supported "slave"
+languages, such as:
+
+ po_slave_languages => { 'fr' => 'Français',
+ 'es' => 'Español',
+ 'de' => 'Deutsch',
+ }
+
+Decide which pages are translatable
+-----------------------------------
+
+The `po_translatable_pages` setting configures what pages are
+translatable. It is a [[ikiwiki/PageSpec]], so you have lots of
+control over what kind of pages are translatable.
+
+The `.po` files are not considered as being translatable, so you don't need to
+worry about excluding them explicitly from this [[ikiwiki/PageSpec]].
+
+Internal links
+--------------
+
+### Links targets
+
+The `po_link_to` option in `ikiwiki.setup` is used to decide how
+internal links should be generated, depending on web server features
+and site-specific preferences.
+
+#### Default linking behavior
+
+If `po_link_to` is unset, or set to `default`, ikiwiki's default
+linking behavior is preserved: `\[[destpage]]` links to the master
+language's page.
+
+#### Link to current language
+
+If `po_link_to` is set to `current`, `\[[destpage]]` links to the
+`destpage`'s version written in the current page's language, if
+available, *i.e.*:
+
+* `foo/destpage/index.LL.html` if `usedirs` is enabled
+* `foo/destpage.LL.html` if `usedirs` is disabled
+
+#### Link to negotiated language
+
+If `po_link_to` is set to `negotiated`, `\[[page]]` links to the
+negotiated preferred language, *i.e.* `foo/page/`.
+
+(In)compatibility notes:
+
+* if `usedirs` is disabled, it does not make sense to set `po_link_to`
+ to `negotiated`; this option combination is neither implemented
+ nor allowed.
+* if the web server does not support Content Negotiation, setting
+ `po_link_to` to `negotiated` will produce a unusable website.
+
+Server support
+==============
+
+Apache
+------
+
+Using Apache `mod_negotiation` makes it really easy to have Apache
+serve any page in the client's preferred language, if available.
+
+Add 'Options MultiViews' to the wiki directory's configuration in Apache.
+
+When `usedirs` is enabled, one has to set `DirectoryIndex index` for
+the wiki context.
+
+Setting `DefaultLanguage LL` (replace `LL` with your default MIME
+language code) for the wiki context can help to ensure
+`bla/page/index.en.html` is served as `Content-Language: LL`.
+
+For details, see [Apache's documentation](http://httpd.apache.org/docs/2.2/content-negotiation.html).
+
+lighttpd
+--------
+
+lighttpd unfortunately does not support content negotiation.
+
+**FIXME**: does `mod_magnet` provide the functionality needed to
+ emulate this?
+
+
+Usage
+=====
+
+Templates
+---------
+
+When `po_link_to` is not set to `negotiated`, one should replace some
+occurrences of `BASEURL` with `HOMEPAGEURL` to get correct links to
+the wiki homepage.
+
+The `ISTRANSLATION` and `ISTRANSLATABLE` variables can be used to
+display things only on translatable or translation pages.
+
+### Display page's versions in other languages
+
+The `OTHERLANGUAGES` loop provides ways to display other languages'
+versions of the same page, and the translations' status.
+
+An example of its use can be found in the default
+`templates/page.tmpl`. In case you want to customize it, the following
+variables are available inside the loop (for every page in):
+
+* `URL` - url to the page
+* `CODE` - two-letters language code
+* `LANGUAGE` - language name (as defined in `po_slave_languages`)
+* `MASTER` - is true (1) if, and only if the page is a "master" page
+* `PERCENT` - for "slave" pages, is set to the translation completeness, in percents
+
+### Display the current translation status
+
+The `PERCENTTRANSLATED` variable is set to the translation
+completeness, expressed in percent, on "slave" pages. It is used by
+the default `templates/page.tmpl`.
+
+Additional PageSpec tests
+-------------------------
+
+This plugin enhances the regular [[ikiwiki/PageSpec]] syntax with some
+additional tests that are documented [[here|ikiwiki/pagespec/po]].
+
+Automatic PO file update
+------------------------
+
+Committing changes to a "master" page:
+
+1. updates the POT file and the PO files for the "slave" languages;
+ the updated PO files are then put under version control;
+2. triggers a refresh of the corresponding HTML slave pages.
+
+Also, when the plugin has just been enabled, or when a page has just
+been declared as being translatable, the needed POT and PO files are
+created, and the PO files are checked into version control.
+
+Discussion pages and other sub-pages
+------------------------------------
+
+Discussion should happen in the language in which the pages are
+written for real, *i.e.* the "master" one. If discussion pages are
+enabled, "slave" pages therefore link to the "master" page's
+discussion page.
+
+Likewise, "slave" pages are not supposed to have sub-pages;
+[[WikiLinks|wikilink]] that appear on a "slave" page therefore link to
+the master page's sub-pages.
+
+Translating
+-----------
+
+One can edit the PO files using ikiwiki's CGI (a message-by-message
+interface could also be implemented at some point).
+
+If [[tips/untrusted_git_push]] is setup, one can edit the PO files in one's
+preferred `$EDITOR`, without needing to be online.
+
+Markup languages support
+------------------------
+
+[[Markdown|mdwn]] is well supported. Some other markup languages supported
+by ikiwiki mostly work, but some pieces of syntax are not rendered
+correctly on the slave pages:
+
+* [[reStructuredText|rst]]: anonymous hyperlinks and internal
+ cross-references
+* [[wikitext]]: conversion of newlines to paragraphs
+* [[creole]]: verbatim text is wrapped, tables are broken
+* [[html]] and LaTeX: not supported yet; the dedicated po4a modules
+ could be used to support them, but they would need a security audit
+* other markup languages have not been tested.
+
+Security
+========
+
+[[po/discussion]] contains a detailed security analysis of this plugin
+and its dependencies.
+
+When using po4a older than 0.35, it is recommended to uninstall
+`Text::WrapI18N` (Debian package `libtext-wrapi18n-perl`), in order to
+avoid a potential denial of service.
+
+TODO
+====
+
+Better links
+------------
+
+Once the fix to
+[[bugs/pagetitle_function_does_not_respect_meta_titles]] from
+[[intrigeri]]'s `meta` branch is merged into ikiwiki upstream, the
+generated links' text will be optionally based on the page titles set
+with the [[meta|plugins/meta]] plugin, and will thus be translatable.
+It will also allow displaying the translation status in links to slave
+pages. Both were implemented, and reverted in commit
+ea753782b222bf4ba2fb4683b6363afdd9055b64, which should be reverted
+once [[intrigeri]]'s `meta` branch is merged.
+
+An integration branch, called `meta-po`, merges [[intrigeri]]'s `po`
+and `meta` branches, and thus has this additional features.
+
+Language display order
+----------------------
+
+Jonas pointed out that one might want to control the order that links to
+other languages are listed, for various reasons. Currently, there is no
+order, as `po_slave_languages` is a hash. It would need to be converted
+to an array to support this. (If twere done, twere best done quickly.)
+--[[Joey]]
+
+Pagespecs
+---------
+
+I was suprised that, when using the map directive, a pagespec of "*"
+listed all the translated pages as well as regular pages. That can
+make a big difference to an existing wiki when po is turned on,
+and seems generally not wanted.
+(OTOH, you do want to match translated pages by
+default when locking pages.) --[[Joey]]
+
+Edit links on untranslated pages
+--------------------------------
+
+If a page is not translated yet, the "translated" version of it
+displays wikilinks to other, existing (but not yet translated?)
+pages as edit links, as if those pages do not exist.
+
+That's really confusing, especially as clicking such a link
+brings up an edit form to create a new, english page.
+
+This is with po_link_to=current or negotiated. With default, it doesn't
+happen..
+
+Also, this may only happen if the page being linked to is coming from an
+underlay, and the underlays lack translation to a given language.
+--[[Joey]]
+
+Double commits of po files
+--------------------------
+
+When adding a new english page, the po files are created, committed,
+and then committed again. The second commit makes this change:
+
+ -"Content-Type: text/plain; charset=utf-8\n"
+ -"Content-Transfer-Encoding: ENCODING"
+ +"Content-Type: text/plain; charset=UTF-8\n"
+ +"Content-Transfer-Encoding: ENCODING\n"
+
+Same thing happens when a change to an existing page triggers a po file
+update. --[[Joey]]
+
+Ugly messages with empty files
+------------------------------
+
+If there are empty .mdwn files, the po plugin displays some ugly messages.
+
+Translation of directives
+-------------------------
+
+If a translated page contains a directive, it may expand to some english
+text, or text in whatever single language ikiwiki is configured to "speak".
+
+Maybe there could be a way to switch ikiwiki to speaking another language
+when building a non-english page? Then the directives would get translated.
+
+Documentation
+-------------
+
+Maybe write separate documentation depending on the people it targets:
+translators, wiki administrators, hackers. This plugin may be complex
+enough to deserve this.
--- /dev/null
+[[!toc ]]
+
+----
+
+# Security review
+
+## Probable holes
+
+_(The list of things to fix.)_
+
+### po4a-gettextize
+
+* po4a CVS 2009-01-16
+* Perl 5.10.0
+
+`po4a-gettextize` uses more or less the same po4a features as our
+`refreshpot` function.
+
+Without specifying an input charset, zzuf'ed `po4a-gettextize` quickly
+errors out, complaining it was not able to detect the input charset;
+it leaves no incomplete file on disk. I therefore had to pretend the
+input was in UTF-8, as does the po plugin.
+
+ zzuf -c -s 13 -r 0.1 \
+ po4a-gettextize -f text -o markdown -M utf-8 -L utf-8 \
+ -m GPL-3 -p GPL-3.pot
+
+Crashes with:
+
+ Malformed UTF-8 character (UTF-16 surrogate 0xdfa4) in substitution
+ iterator at /usr/share/perl5/Locale/Po4a/Po.pm line 1449.
+ Malformed UTF-8 character (fatal) at /usr/share/perl5/Locale/Po4a/Po.pm
+ line 1449.
+
+An incomplete pot file is left on disk. Unfortunately Po.pm tells us
+nothing about the place where the crash happens.
+
+> It's fairly standard perl behavior when fed malformed utf-8. As long
+> as it doesn't crash ikiwiki, it's probably acceptable. Ikiwiki can
+> do some similar things itself when fed malformed utf-8 (doesn't
+> crash tho) --[[Joey]]
+
+----
+
+## Potential gotchas
+
+_(Things not to do.)_
+
+
+### Blindly activating more po4a format modules
+
+The format modules we want to use have to be checked, as not all are
+safe (e.g. the LaTeX module's behaviour is changed by commands
+included in the content); they may use regexps generated from
+the content.
+
+----
+
+## Hopefully non-holes
+
+_(AKA, the assumptions that will be the root of most security holes...)_
+
+### PO file features
+
+No [documented](http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files)
+directive that can be put in po files is supposed to cause mischief
+(ie, include other files, run commands, crash gettext, whatever).
+
+### gettext
+
+#### Security history
+
+The only past security issue I could find in GNU gettext is
+[CVE-2004-0966](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-0966),
+*i.e.* [Debian bug #278283](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=278283):
+the autopoint and gettextize scripts in the GNU gettext package (1.14
+and later versions) may allow local users to overwrite files via
+a symlink attack on temporary files.
+
+This plugin would not have allowed to exploit this bug, as it does not
+use, either directly or indirectly, the faulty scripts.
+
+Note: the lack of found security issues can either indicate that there
+are none, or reveal that no-one ever bothered to find or publish them.
+
+#### msgmerge
+
+`refreshpofiles()` runs this external program.
+
+* I was not able to crash it with `zzuf`.
+* I could not find any past security hole.
+
+#### msgfmt
+
+`isvalidpo()` runs this external program.
+
+* I was not able to make it behave badly using zzuf: it exits cleanly
+ when too many errors are detected.
+* I could not find any past security hole.
+
+### po4a
+
+#### Security history
+
+The only past security issue I could find in po4a is
+[CVE-2007-4462](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-4462):
+`lib/Locale/Po4a/Po.pm` in po4a before 0.32 allowed local users to
+overwrite arbitrary files via a symlink attack on the
+gettextization.failed.po temporary file.
+
+This plugin would not have allowed to exploit this bug, as it does not
+use, either directly or indirectly, the faulty `gettextize` function.
+
+Note: the lack of found security issues can either indicate that there
+are none, or reveal that no-one ever bothered to find or publish them.
+
+#### General feeling
+
+Are there any security issues on running po4a on untrusted content?
+
+To say the least, this issue is not well covered, at least publicly:
+
+* the documentation does not talk about it;
+* grep'ing the source code for `security` or `trust` gives no answer.
+
+On the other hand, a po4a developer answered my questions in
+a convincing manner, stating that processing untrusted content was not
+an initial goal, and analysing in detail the possible issues.
+The following analysis was done with his help.
+
+#### Details
+
+* the core (`Po.pm`, `Transtractor.pm`) should be safe
+* po4a source code was fully checked for other potential symlink
+ attacks, after discovery of one such issue
+* the only external program run by the core is `diff`, in `Po.pm` (in
+ parts of its code we don't use)
+* `Locale::gettext` is only used to display translated error messages
+* Nicolas François "hopes" `DynaLoader` is safe, and has "no reason to
+ think that `Encode` is not safe"
+* Nicolas François has "no reason to think that `Encode::Guess` is not
+ safe". The po plugin nevertheless avoids using it by defining the
+ input charset (`file_in_charset`) before asking `TransTractor` to
+ read any file. NB: this hack depends on po4a internals.
+
+##### Locale::Po4a::Text
+
+* does not run any external program
+* only `do_paragraph()` builds regexp's that expand untrusted
+ variables; according to [[Joey]], this is "Freaky code, but seems ok
+ due to use of `quotementa`".
+
+##### Text::WrapI18N
+
+`Text::WrapI18N` can cause DoS
+([Debian bug #470250](http://bugs.debian.org/470250)).
+It is optional, and we do not need the features it provides.
+
+If a recent enough po4a (>=0.35) is installed, this module's use is
+fully disabled. Else, the wiki administrator is warned about this
+at runtime.
+
+##### Term::ReadKey
+
+`Term::ReadKey` is not a hard dependency in our case, *i.e.* po4a
+works nicely without it. But the po4a Debian package recommends
+`libterm-readkey-perl`, so it will probably be installed on most
+systems using the po plugin.
+
+`Term::ReadKey` has too far reaching implications for us to
+be able to guarantee anything wrt. security.
+
+If a recent enough po4a (>=2009-01-15 CVS, which will probably be
+released as 0.35) is installed, this module's use is fully disabled.
+
+##### Fuzzing input
+
+###### po4a-translate
+
+* po4a CVS 2009-01-16
+* Perl 5.10.0
+
+`po4a-translate` uses more or less the same po4a features as our
+`filter` function.
+
+Without specifying an input charset, same behaviour as
+`po4a-gettextize`, so let's specify UTF-8 as input charset as of now.
+
+`LICENSES` is a 21M file containing 100 concatenated copies of all the
+files in `/usr/share/common-licenses/`; I had no existing PO file or
+translated versions at hand, which renders these tests
+quite incomplete.
+
+ zzuf -cv -s 0:10 -r 0.001:0.3 \
+ po4a-translate -d -f text -o markdown -M utf-8 -L utf-8 \
+ -k 0 -m LICENSES -p LICENSES.fr.po -l test.fr
+
+... seems to lose the fight, at the `readpo(LICENSES.fr.po)` step,
+against some kind of infinite loop, deadlock, or any similar beast.
+
+The root of this bug lies in `Text::WrapI18N`, see the corresponding
+section.
+
+
+----
+
+## Fixed holes
+
+
+----
+
+# original contrib/po page, with old commentary
+
+I've been working on a plugin called "po", that adds support for multi-lingual wikis,
+translated with gettext, using [po4a](http://po4a.alioth.debian.org/).
+
+More information:
+
+* It can be found in my "po" branch:
+ `git clone git://gaffer.ptitcanardnoir.org/ikiwiki.git`
+* It is self-contained, *i.e.* it does not modify ikiwiki core at all.
+* It is documented (including TODO and plans for next work steps) in
+ `doc/plugins/po.mdwn`, which can be found in the same branch.
+* No public demo site is available so far, I'm working on this.
+
+My plan is to get this plugin clean enough to be included in ikiwiki.
+
+The current version is a proof-of-concept, mature enough for me to dare submitting it here,
+but I'm prepared to hear various helpful remarks, and to rewrite parts of it as needed.
+
+Any thoughts on this?
+
+> Well, I think it's pretty stunning what you've done here. Seems very
+> complete and well thought out. I have not read the code in great detail
+> yet.
+>
+> Just using po files is an approach I've never seen tried with a wiki. I
+> suspect it will work better for some wikis than others. For wikis that
+> just want translations that match the master language as closely as
+> possible and don't wander off and diverge, it seems perfect. (But what happens
+> if someone edits the Discussion page of a translated page?)
+>
+> Please keep me posted, when you get closer to having all issues solved
+> and ready for merging I can do a review and hopefully help with the
+> security items you listed. --[[Joey]]
+
+>> Thanks a lot for your quick review, it's reassuring to hear such nice words
+>> from you. I did not want to design and write a full translation system, when
+>> tools such as gettext/po4a already have all the needed functionality, for cases
+>> where the master/slave languages paradigm fits.
+>> Integrating these tools into ikiwiki plugin system was a pleasure.
+>>
+>> I'll tell you when I'm ready for merging, but in the meantime,
+>> I'd like you to review the changes I did to the core (3 added hooks).
+>> Can you please do this? If not, I'll go on and hope I'm not going to far in
+>> the wrong direction.
+>>
+>>> Sure.. I'm not completly happy with any of the hooks since they're very
+>>> special purpose, and also since `run_hooks` is not the best interface
+>>> for a hook that modifies a variable, where only the last hook run will
+>>> actually do anything. It might be better to just wrap
+>>> `targetpage`, `bestlink`, and `beautify_urlpath`. But, I noticed
+>>> the other day that such wrappers around exported functions are only visible by
+>>> plugins loaded after the plugin that defines them.
+>>>
+>>> Update: Take a look at the new "Function overriding" section of
+>>> [[plugins/write]]. I think you can just inject wrappers about a few ikiwiki
+>>> functions, rather than adding hooks. The `inject` function is pretty
+>>> insane^Wlow level, but seems to work great. --[[Joey]]
+>>>
+>>>> Thanks a lot, it seems to be a nice interface for what I was trying to achieve.
+>>>> I may be forced to wait two long weeks before I have a chance to confirm
+>>>> this. Stay tuned. --[[intrigeri]]
+>>>>
+>>>>> I've updated the plugin to use `inject`. It is now fully self-contained,
+>>>>> and does not modify the core anymore. --[[intrigeri]]
+>>
+>> The Discussion pages issue is something I am not sure about yet. But I will
+>> probably decide that "slave" pages, being only translations, don't deserve
+>> a discussion page: the discussion should happen in the language in which the
+>> pages are written for real, which is the "master" one. --[[intrigeri]]
+>>
+>> I think that's a good decision, you don't want to translate discussion,
+>> and if the discussion page turns out multilingual, well, se la vi. ;-)
+>>
+>> Relatedly, what happens if a translated page has a broken link, and you
+>> click on it to edit it? Seems you'd first have to create a master page
+>> and could only then translate it, right? I wonder if this will be clear
+>> though to the user.
+>>
+>>> Right: a broken link points to the URL that allows to create
+>>> a page that can either be a new master page or a non-translatable
+>>> page, depending on `po_translatable_pages` value. The best
+>>> solution I can thing of is to use [[plugins/edittemplate]] to
+>>> insert something like "Warning: this is a master page, that must
+>>> be written in $MASTER_LANGUAGE" into newly created master pages,
+>>> and maybe another warning message on newly created
+>>> non-translatable pages. It seems quite doable to me, but in order
+>>> to avoid breaking existing functionality, it implies to hack a bit
+>>> [[plugins/edittemplate]] so that multiple templates can be
+>>> inserted at page creation time. [[--intrigeri]]
+>>>
+>>>> I implemented such a warning using the formbuilder_setup hook.
+>>>> --[[intrigeri]]
+>>
+>> And also, is there any way to start a translation of a page into a new
+>> lanauge using the web interface?
+>>
+>>> When a new language is added to `po_slave_languages`, a rebuild is
+>>> triggered, and all missing PO files are created and checked into
+>>> VCS. An unpriviledged wiki user can not add a new language to
+>>> `po_slave_languages`, though. One could think of adding the needed
+>>> interface to translate a page into a yet-unsupported slave
+>>> language, and this would automagically add this new language to
+>>> `po_slave_languages`. It would probably be useful in some
+>>> usecases, but I'm not comfortable with letting unpriviledged wiki
+>>> users change the wiki configuration as a side effect of their
+>>> actions; if this were to be implemented, special care would be
+>>> needed. [[--intrigeri]]
+>>>
+>>>> Actually I meant into any of the currently supported languages.
+>>>> I guess that if the template modification is made, it will list those
+>>>> languages on the page, and if a translation to a language is missing,
+>>>> the link will allow creating it?
+>>>>
+>>>>> Any translation page always exist for every supported slave
+>>>>> language, even if no string at all have been translated yet.
+>>>>> This implies the po plugin is especially friendly to people who
+>>>>> prefer reading in their native language if available, but don't
+>>>>> mind reading in English else.
+>>>>>
+>>>>> While I'm at it, there is a remaining issue that needs to be
+>>>>> sorted out: how painful it could be for non-English speakers
+>>>>> (assuming the master language is English) to be perfectly able
+>>>>> to navigate between translation pages supposed to be written in
+>>>>> their own language, when their translation level is most
+>>>>> often low.
+>>>>>
+>>>>> (It is currently easy to display this status on the translation
+>>>>> page itself, but then it's too late, and how frustrating to load
+>>>>> a page just to realize it's actually not translated enough for
+>>>>> you. The "other languages" loop also allows displaying this
+>>>>> information, but it is generally not the primary
+>>>>> navigation tool.)
+>>>>>
+>>>>> IMHO, this is actually a social problem (i.e. it's no use adding
+>>>>> a language to the supported slave ones if you don't have the
+>>>>> manpower to actually do the translations), that can't be fully
+>>>>> solved by technical solutions, but I can think of some hacks
+>>>>> that would limit the negative impact: a given translation's
+>>>>> status (currently = percent translated) could be displayed next
+>>>>> to the link that leads to it; a color code could as well be used
+>>>>> ("just" a matter of adding a CSS id or class to the links,
+>>>>> depending on this variable). As there is already work to be done
+>>>>> to have the links text generation more customizable through
+>>>>> plugins, I could do both at the same time if we consider this
+>>>>> matter to be important enough. --[[intrigeri]]
+>>>>>
+>>>>>> The translation status in links is now implemented in my
+>>>>>> `po`branch. It requires my `meta` branch changes to
+>>>>>> work, though. I consider the latter to be mature enough to
+>>>>>> be merged. --[[intrigeri]]
+
+>> FWIW, I'm tracking your po branch in ikiwiki master git in the po
+>> branch. One thing I'd like to try in there is setting up a translated
+>> basewiki, which seems like it should be pretty easy to do, and would be
+>> a great demo! --[[Joey]]
+>>
+>>> I have a complete translation of basewiki into danish, available merged into
+>>> ikiwiki at git://source.jones.dk/ikiwiki-upstream (branch underlay-da), and am working with
+>>> others on preparing one in german. For a complete translated user
+>>> experience, however, you will also need templates translated (there are a few
+>>> translatable strings there too). My most recent po4a Markdown improvements
+>>> adopted upstream but not yet in Debian (see
+>>> [bug#530574](http://bugs.debian.org/530574)) correctly handles multiple
+>>> files in a single PO which might be relevant for template translation handling.
+>>> --[[JonasSmedegaard]]
+>>
+>>> I've merged your changes into my own branch, and made great
+>>> progress on the various todo items. Please note my repository
+>>> location has changed a few days ago, my user page was updated
+>>> accordingly, but I forgot to update this page at the same time.
+>>> Hoping it's not too complicated to relocated an existing remote...
+>>> (never done that, I'm a Git beginner as well as a Perl
+>>> newbie) --[[intrigeri]]
+>>>>
+>>>> Just a matter of editing .git/config, thanks for the heads up.
+>>>>>
+>>>>> Joey, please have a look at my branch, your help would be really
+>>>>> welcome for the security research, as I'm almost done with what
+>>>>> I am able to do myself in this area. --[[intrigeri]]
+>>>>>>
+>>>>>> I came up with a patch for the WrapI18N issue --[[Joey]]
+
+I've set this plugin development aside for a while. I will be back and
+finish it at some point in the first quarter of 2009. --[[intrigeri]]
+
+> Abstract: Joey, please have a look at my po and meta branches.
+>
+> Detailed progress report:
+>
+> * it seems the po branch in your repository has not been tracking my
+> own po branch for two months. any config issue?
+> * all the plugin's todo items have been completed, robustness tests
+> done
+> * I've finished the detailed security audit, and the fix for po4a
+> bugs has entered upstream CVS last week
+> * I've merged your new `checkcontent` hook with the `cansave` hook
+> I previously introduced in my own branch; blogspam plugin updated
+> accordingly
+> * the rename hook changes we discussed elsewhere are also part of my
+> branch
+> * I've introduced two new hooks (`canremove` and `canrename`), not
+> a big deal; IMHO, they extend quite logically the plugin interface
+> * as highlighted on [[bugs/pagetitle_function_does_not_respect_meta_titles]],
+> my `meta` branch contains a new feature that is really useful in a
+> translatable wiki
+>
+> As a conclusion, I'm feeling that my branches are ready to be
+> merged; only thing missing, I guess, are a bit of discussion and
+> subsequent adjustments.
+>
+> --[[intrigeri]]
+
+> I've looked it over and updated my branch with some (untested)
+> changes.
+>
+>> I've merged your changes into my branch. Only one was buggy.
+>
+> Sorry, I'd forgotten about your cansave hook.. sorry for the duplicate
+> work there.
+>
+> Reviewing the changes, mostly outside of `po.pm`, I have
+> the following issues.
+>
+> * renamepage to renamelink change would break the ikiwiki
+> 3.x API, which I've promised not to do, so needs to be avoided
+> somehow. (Sorry, I guess I dropped the ball on not getting this
+> API change in before cutting 3.0..)
+>>
+>> Fixed, see [[todo/need_global_renamepage_hook]].
+>>
+> * I don't understand the parentlinks code change and need to figure it
+> out. Can you explain what is going on there?
+>>
+>> I'm calling `bestlink` there so that po's injected `bestlink` is
+>> run. This way, the parent links of a page link to the parent page
+>> version in the proper language, depending on the
+>> `po_link_to=current` and `po_link_to=negotiated` settings.
+>> Moreover, when using my meta branch enhancements plus meta title to
+>> make pages titles translatable, this small patch is needed to get
+>> the translated titles into parentlinks.
+>>
+> * canrename's mix of positional and named parameters is way too
+> ugly to get into an ikiwiki API. Use named parameters
+> entirely. Also probably should just use named parameters
+> for canremove.
+> * `skeleton.pm.example`'s canrename needs fixing to use either
+> the current or my suggested parameters.
+>>
+>> Done.
+>>
+> * I don't like the exporting of `%backlinks` and `$backlinks_calculated`
+> (the latter is exported but not used).
+>>
+>> The commit message for 85f865b5d98e0122934d11e3f3eb6703e4f4c620
+>> contains the rationale for this change. I guess I don't understand
+>> the subtleties of `our` use, and perldoc does not help me a lot.
+>> IIRC, I actually did not use `our` to "export" these variables, but
+>> rather to have them shared between `Render.pm` uses.
+>>
+>>> My wording was unclear, I meant exposing. --[[Joey]]
+>>>
+>>>> I guess I still don't know Perl's `our` enough to understand clearly.
+>>>> No matter whether these variables are declared with `my` or `our`,
+>>>> any plugin can `use IkiWiki::Render` and then access
+>>>> `$IkiWiki::backlinks`, as already does e.g. the pagestat plugin.
+>>>> So I guess your problem is not with letting plugins use these
+>>>> variables, but with them being visible for every piece of
+>>>> (possibly external) code called from `Render.pm`. Am I right?
+>>>> If I understand clearly, using a brace block to lexically enclose
+>>>> these two `our` declarations, alongside with the `calculate_backlinks`
+>>>> and `backlinks` subs definitions, would be a proper solution, wouldn't
+>>>> it? --[[intrigeri]]
+>>>>
+>>>>> No, %backlinks and the backlinks() function are not the same thing.
+>>>>> The variable is lexically scoped; only accessible from inside
+>>>>> `Render.pm` --[[Joey]]
+>>>>
+> * What is this `IkiWiki::nicepagetitle` and why are you
+> injecting it into that namespace when only your module uses it?
+> Actually, I can't even find a caller of it in your module.
+>>
+>> I guess you should have a look to my `meta` branch and to
+>> [[bugs/pagetitle_function_does_not_respect_meta_titles]] in order
+>> to understand this :)
+>>
+>>> It would probably be good if I could merge this branch without
+>>> having to worry about also immediatly merging that one. --[[Joey]]
+>>>
+>>>> I removed all dependencies on my `meta` branch from the `po` one.
+>>>> This implied removing the `po_translation_status_in_links` and
+>>>> `po_strictly_refresh_backlinks` features, and every link text is now
+>>>> displayed in the master language. I believe the removed features really
+>>>> enhance user experience of a translatable wiki, that's why I was
+>>>> initially supposing the `meta` branch would be merged first.
+>>>> IMHO, we'll need to come back to this quite soon after `po` is merged.
+>>>> --[[intrigeri]]
+>>>>
+>>>> Maybe you should keep those features in a meta-po branch?
+>>>> I did a cursory review of your meta last night, have some issues with it,
+>>>> but this page isn't the place for a detailed review. --[[Joey]]
+>>>>
+>>>>> Done. --[[intrigeri]]
+>>>
+> * I'm very fearful of the `add_depends` in `postscan`.
+> Does this make every page depend on every page that links
+> to it? Won't this absurdly bloat the dependency pagespecs
+> and slow everything down? And since nicepagetitle is given
+> as the reason for doing it, and nicepagetitle isn't used,
+> why do it?
+>>
+>> As explained in the 85f865b5d98e0122934d11e3f3eb6703e4f4c620 log:
+>> this feature hits performance a bit. Its cost was quite small in my
+>> real-world use-cases (a few percents bigger refresh time), but
+>> could be bigger in worst cases. When using the po plugin with my
+>> meta branch changes (i.e. the `nicepagetitle` thing), and having
+>> enabled the option to display translation status in links, this
+>> maintains the translation status up-to-date in backlinks. Same when
+>> using meta title to make the pages titles translatable. It does
+>> help having a nice and consistent translated wiki, but as it can
+>> also involve problems, I just turned it into an option.
+>>
+>>> This has been completely removed for now due to the removal of
+>>> the dependency on my `meta` branch. --[[intrigeri]]
+>>
+> * The po4a Suggests should be versioned to the first version
+> that can be used safely, and that version documented in
+> `plugins/po.mdwn`.
+>>
+>> Done.
+>>
+>> --[[intrigeri]]
+>
+> --[[Joey]]
+
+I reverted the `%backlinks` and `$backlinks_calculated` exposing.
+The issue they were solving probably will arise again when I'll work
+on my meta branch again (i.e. when the simplified po one is merged),
+but the po thing is supposed to work without these ugly `our`.
+Seems like it was the last unaddressed item from Joey's review, so I'm
+daring a timid "please pull"... or rather, please review again :)
+--[[intrigeri]]
+
+> Ok, I've reviewed and merged into my own po branch. It's looking very
+> mergeable.
+>
+> * Is it worth trying to fix compatability with `indexpages`?
+>>
+>> Supporting `usedirs` being enabled or disabled was already quite
+>> hard IIRC, so supporting all four combinations of `usedirs` and
+>> `indexpages` settings will probably be painful. I propose we forget
+>> about it until someone reports he/she badly needs it, and then
+>> we'll see what can be done.
+>>
+> * Would it make sense to go ahead and modify `page.tmpl` to use
+> OTHERLANGUAGES and PERCENTTRANSLATED, instead of documenting how to modify it?
+>>
+>> Done in my branch.
+>>
+> * Would it be better to disable po support for pages that use unsupported
+> or poorly-supported markup languages?
+>
+>> I prefer keeping it enabled, as:
+>>
+>> * most wiki markups "almost work"
+>> * when someone needs one of these to be fully supported, it's not
+>> that hard to add dedicated support for it to po4a; if it were
+>> disabled, I fear the ones who could do this would maybe think
+>> it's blandly impossible and give up.
+>>
+
+> * What's the reasoning behind checking that the link plugin
+> is enabled? AFAICS, the same code in the scan hook should
+> also work when other link plugins like camelcase are used.
+>>
+>> That's right, fixed.
+>>
+> * In `pagetemplate` there is a comment that claims the code
+> relies on `genpage`, but I don't see how it does; it seems
+> to always add a discussion link?
+>>
+>> It relies on IkiWiki::Render's `genpage` as this function sets the
+>> `discussionlink` template param iff it considers a discussion link
+>> should appear on the current page. That's why I'm testing
+>> `$template->param('discussionlink')`.
+>>
+>>> Maybe I was really wondering why it says it could lead to a broken
+>>> link if the cgiurl is disabled. I think I see why now: Discussionlink
+>>> will be set to a link to an existing disucssion page, even if cgi is
+>>> disabled -- but there's no guarantee of a translated discussion page
+>>> existing in that case. *However*, htmllink actually checks
+>>> for this case, and will avoid generating a broken link so AFAICS, the
+>>> comment is actually innacurate.. what will really happen in this case
+>>> is discussionlink will be set to a non-link translation of
+>>> "discussion". Also, I consider `$config{cgi}` and `%links` (etc)
+>>> documented parts of the plugin interface, which won't change; po could
+>>> rely on them to avoid this minor problem. --[[Joey]]
+>>>>
+>>>> Done in my branch. --[[intrigeri]]
+>>>>
+>
+> * Is there any real reason not to allow removing a translation?
+> I'm imagining a spammy translation, which an admin might not
+> be able to fix, but could remove.
+>>
+>> On the other hand, allowing one to "remove" a translation would
+>> probably lead to misunderstandings, as such a "removed" translation
+>> page would appear back as soon as it is "removed" (with no strings
+>> translated, though). I think an admin would be in a position to
+>> delete the spammy `.po` file by hand using whatever VCS is in use.
+>> Not that I'd really care, but I am slightly in favour of the way
+>> it currently works.
+>>
+>>> That would definitly be confusing. It sounds to me like if we end up
+>>> needing to allow web-based deletion of spammy translations, it will
+>>> need improvements to the deletion UI to de-confuse that. It's fine to
+>>> put that off until needed --[[Joey]]
+>>
+> * Re the meta title escaping issue worked around by `change`.
+> I suppose this does not only affect meta, but other things
+> at scan time too. Also, handling it only on rebuild feels
+> suspicious -- a refresh could involve changes to multiple
+> pages and trigger the same problem, I think. Also, exposing
+> this rebuild to the user seems really ugly, not confidence inducing.
+>
+> So I wonder if there's a better way. Such as making po, at scan time,
+> re-run the scan hooks, passing them modified content (either converted
+> from po to mdwn or with the escaped stuff cheaply de-escaped). (Of
+> course the scan hook would need to avoid calling itself!)
+>
+> (This doesn't need to block the merge, but I hope it can be addressed
+> eventually..)
+>
+> --[[Joey]]
+>>
+>> I'll think about it soon.
+>>
+>> --[[intrigeri]]
+>>
+>>> Did you get a chance to? --[[Joey]]
+
+ * As discussed at [[todo/l10n]] the templates needs to be translatable too. They
+ should be treated properly by po4a using the markdown option - at least with my
+ later patches in [bug#530574](http://bugs.debian.org/530574)) applied.
+
+ * It seems to me that the po plugin (and possibly other parts of ikiwiki) wrongly
+ uses gettext. As I understand it, gettext (as used currently in ikiwiki) always
+ lookup a single language, That might make sense for a single-language site, but
+ multilingual sites should emit all strings targeted at the web output in each own
+ language.
+
+ So generally the system language (used for e.g. compile warnings) should be separated
+ from both master language and slave languages.
+
+ Preferrably the gettext subroutine could be extended to pass locale as optional
+ secondary parameter overriding the default locale (for messages like "N/A" as
+ percentage in po plugin). Alternatively (with above mentioned template support)
+ all such strings could be externalized as templates that can then be localized.
+
+# Robustness tests
+
+### Enabling/disabling the plugin
+
+* enabling the plugin with `po_translatable_pages` set to blacklist: **OK**
+* enabling the plugin with `po_translatable_pages` set to whitelist: **OK**
+* enabling the plugin without `po_translatable_pages` set: **OK**
+* disabling the plugin: **OK**
+
+### Changing the plugin config
+
+* adding existing pages to `po_translatable_pages`: **OK**
+* removing existing pages from `po_translatable_pages`: **OK**
+* adding a language to `po_slave_languages`: **OK**
+* removing a language from `po_slave_languages`: **OK**
+* changing `po_master_language`: **OK**
+* replacing `po_master_language` with a language previously part of
+ `po_slave_languages`: needs two rebuilds, but **OK** (this is quite
+ a perverse test actually)
+
+### Creating/deleting/renaming pages
+
+All cases of master/slave page creation/deletion/rename, both via RCS
+and via CGI, have been tested.
+
+### Misc
+
+* general test with `usedirs` disabled: **OK**
+* general test with `indexpages` enabled: **not OK**
+* general test with `po_link_to=default` with `userdirs` enabled: **OK**
+* general test with `po_link_to=default` with `userdirs` disabled: **OK**
+
+Duplicate %links ?
+------------------
+
+I notice code in the scan hook that seems to assume
+that %links will accumulate duplicate links for a page.
+That used to be so, but the bug was fixed. Does this mean
+that po might be replacing the only link on a page, in error?
+--[[Joey]]
+
+> It would replace it. The only problematic case is when another
+> plugin has its own reasons, in its `scan` hook, to add a page
+> that is already there to `$links{$page}`. This other plugin's
+> effect might then be changed by po's `scan` hook... which could
+> be either good (better overall l10n) or bad (break the other
+> plugin's goal). --[[intrigeri]]
+
+>> Right.. well, the cases where links are added is very small.
+>> Grepping for `add_link`, it's just done by link, camelcase, meta, and
+>> tag. All of these are supposed to work just link regular links
+>> so I'd think that is ok. We could probably remove the currently scary
+>> comment about only wanting to change the first link. --[[Joey]]
+
+>>> Commit 3c2bffe21b91684 in my po branch does this. --[[intrigeri]]
+>>>> Cherry-picked --[[Joey]]
-[[template id=plugin name=poll author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=poll author="[[Joey]]"]]
+[[!tag type/web]]
-This plugin allows you to create online polls in the wiki. Here's an
-example use:
-
- \[[poll 0 "red" 0 "green" 0 "blue"]]
-
-The numbers indicate how many users voted for that choice. When a user
-votes for a choice in the poll, the page is modified and the number
-incremented.
-
-While some basic precautions are taken to prevent users from accidentially
-voting twice, this sort of poll should not be counted on to be very
-accurate; all the usual concerns about web based polling apply. Unless the
-page that the poll is in is locked, users can even edit the page and change
-the numbers!
-
-Parameters:
-
-* `open` - Whether voting is still open. Set to "no" to close the poll to
- voting.
-* `total` - Show total number of votes at bottom of poll. Default is "yes".
-* `percent` - Whether to display percents. Default is "yes".
+This plugin provides the [[ikiwiki/directive/poll]] [[ikiwiki/directive]],
+which allows inserting an online poll into a page.
-[[template id=plugin name=polygen author="Enrico Zini"]]
-[[tag type/fun]]
+[[!template id=plugin name=polygen author="Enrico Zini"]]
+[[!tag type/fun]]
-This plugin allows inserting text generated by polygen into a wiki page.
-For example:
+This plugin provides the [[ikiwiki/directive/polygen]] [[ikiwiki/directive]],
+which allows inserting text generated by polygen into a wiki page.
- \[[polygen grammar="genius"]]
-
-It's also possible to specify a starting nonterminal for the grammar by
-including `symbol="text"` in the directive.
-
-[[if test="enabled(polygen)" then="""
+[[!if test="enabled(polygen)" then="""
----
Here are a few notes about ikiwiki, courtesy of polygen:
-Ikiwiki is internally based on a [[polygen grammar="designpatterns"]]
-coupled to a [[polygen grammar="designpatterns"]], as described in
-"[[polygen grammar="paper"]]" by [[polygen grammar="nipponame"]] of
-[[polygen grammar="boyband"]].
+Ikiwiki is internally based on a [[!polygen grammar="designpatterns"]]
+coupled to a [[!polygen grammar="designpatterns"]], as described in
+"[[!polygen grammar="paper"]]" by [[!polygen grammar="nipponame"]] of
+[[!polygen grammar="boyband"]].
Ikiwiki reviews:
<ul>
-<li>[[polygen grammar="reviews"]]</li>
-<li>[[polygen grammar="reviews"]]</li>
-<li>[[polygen grammar="reviews"]]</li>
+<li>[[!polygen grammar="reviews"]]</li>
+<li>[[!polygen grammar="reviews"]]</li>
+<li>[[!polygen grammar="reviews"]]</li>
</ul>
"""]]
-[[template id=plugin name=postsparkline author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=postsparkline author="[[Joey]]"]]
+[[!tag type/chrome]]
-This plugin uses the [[sparkline]] plugin to create a sparkline of
+This plugin provides the [[ikiwiki/directive/postsparkline]] [[ikiwiki/directive]].
+It uses the [[sparkline]] plugin to create a sparkline of
statistics about a set of pages, such as posts to a blog.
-# examples
-
- Post interval:
- \[[postsparkline pages="blog/* and !*/Discussion" max=100
- formula=interval style=bar barwidth=2 barspacing=1 height=13]]
-
- Posts per month this year:
- \[[postsparkline pages="blog/* and !*/Discussion" max=12
- formula=permonth style=bar barwidth=2 barspacing=1 height=13]]
-
-# usage
-
-All options aside fron the `pages`, `max`, `formula`, `time`, and `color`
-options are passed on to the sparkline plugin.
-
-You don't need to specify any data points (though you can if you want to).
-Instead, data points are automatically generated based on the creation
-times of pages matched by the specified `pages` [[ikiwiki/PageSpec]]. A
-maximum of `max` data points will be generated.
-
-The `formula` parameter controls the formula used to generate data points.
-Available forumlae:
-
-* `interval` - The height of each point represents how long it has been
- since the previous post.
-* `perday` - Each point represents a day; the height represents how
- many posts were made that day.
-* `permonth` - Each point represents a month; the height represents how
- many posts were made that month.
-* `peryear` - Each point represents a day; the height represents how
- many posts were made that year.
-
-The `time` parameter has a default value of "ctime", since forumae use
-the creation times of pages by default. If you instead want
-them to use the modification times of pages, set it to "mtime".
-
-To change the color used to draw the sparkline, use the `color` parameter.
-For example, "color=red".
-
# adding formulae
Additional formulae can be added without modifying this plugin by writing
-[[template id=plugin name=prettydate author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=prettydate author="[[Joey]]"]]
+[[!tag type/date]]
Enabling this plugin changes the dates displayed on pages in the wiki to
a format that is nice and easy to read. Examples: "late Wednesday evening,
configuration variable in the setup file. `%X` will be expanded to the
prettified time value. The default prettydateformat is `"%X, %B %o, %Y"`.
-This plugin uses the [[cpan TimeDate]] perl module.
+This plugin uses the [[!cpan TimeDate]] perl module.
--- /dev/null
+[[!template id=plugin name=progress author="[[Will]]"]]
+[[!tag type/meta]]
+
+This plugin provides the [[ikiwiki/directive/progress]]
+[[ikiwiki/directive]], which generates a progress bar.
-[[template id=plugin name=rawhtml author="[[Joey]]"]]
-[[tag type/html type/format]]
+[[!template id=plugin name=rawhtml author="[[Joey]]"]]
+[[!tag type/html type/format]]
This plugin changes how ikiwiki handles html files, making it treat html
or xhtml files not as source files but as data files that are copied
-[[template id=plugin name=recentchanges core=1 author="[[Joey]]"]]
+[[!template id=plugin name=recentchanges core=1 author="[[Joey]]"]]
This plugin examines the [[revision_control_system|rcs]] history and
generates a page describing each recent change made to the wiki. These
Typically only the RecentChanges page will use the pages generated by this
plugin, but you can use it elsewhere too if you like. It's used like this:
- \[[inline pages="internal(recentchanges/change_*)"
+ \[[!inline pages="internal(recentchanges/change_*)"
template=recentchanges show=0]]
Here's an example of how to show only changes to "bugs/*".
This matches against the title of the change, which includes a list of
modified pages.
- \[[inline pages="internal(recentchanges/change_*) and title(*bugs/*)"
+ \[[!inline pages="internal(recentchanges/change_*) and title(*bugs/*)"
template=recentchanges show=0]]
Here's an example of how to show only changes that Joey didn't make.
(Joey commits sometimes as user `joey`, and sometimes via openid.)
- \[[inline pages="internal(recentchanges/change_*) and
+ \[[!inline pages="internal(recentchanges/change_*) and
!author(joey) and !author(http://joey.kitenet.net*)"
template=recentchanges show=0]]
+
+If you want to generate feeds for the RecentChanges page, you have to use
+[[`rss`_or_`atom`_in_the_setup_file|/todo/minor adjustment to setup documentation for recentchanges feeds]].
-[[template id=plugin name=recentchangesdiff core=0 author="[[Joey]]"]]
+[[!template id=plugin name=recentchangesdiff core=0 author="[[Joey]]"]]
This plugin extends the [[recentchanges]] plugin, adding a diff for each
change. The diffs are by default hidden from display on the recentchanges
--- /dev/null
+[[!template id=plugin name=relativedate author="[[Joey]]"]]
+[[!tag type/date]]
+
+This plugin lets dates be displayed in relative form. Examples: "2 days ago",
+"1 month and 3 days ago", "30 minutes ago". Hovering over the date will
+cause a tooltip to pop up with the absolute date.
+
+This only works in browsers with javascript enabled; other browsers will
+show the absolute date instead. Also, this plugin can be used with other
+plugins like [[prettydate]] that change how the absolute date is displayed.
+
+If this plugin is enabled, you may also add relative dates to pages in the
+wiki, by using html elements in the "relativedate" class. For example, this
+will display as a relative date:
+
+ <span class="relativedate">Tue Jan 20 12:00:00 EDT 2009</span>
--- /dev/null
+[[!template id=plugin name=remove core=0 author="[[Joey]]"]]
+[[!tag type/web]]
+
+This plugin allows pages or other files to be removed using the web
+interface.
+
+Users can only remove things that they are allowed to edit or upload.
--- /dev/null
+[[!template id=plugin name=rename core=0 author="[[Joey]]"]]
+[[!tag type/web]]
+
+This plugin allows pages or other files to be renamed using the web
+interface.
+
+Users can only rename things that they are allowed to edit or upload.
+
+It attempts to fix up links to renamed pages, and if some links cannot be
+fixed up, the pages that contain the broken links will be displayed after
+the rename.
--- /dev/null
+[[!template id=plugin name=repolist author="[[Joey]]"]]
+[[!tag type/useful]]
+
+This plugin allows you to configure ikiwiki with the location of
+[[rcs]] repositories for your wiki's source. This is done via the
+"repositories" setting in the setup file. Once you tell it where the source
+to your wiki can be downloaded from, this information can be published on
+your wiki in various ways.
+
+This plugin supports the [rel-vcs-*](http://kitenet.net/~joey/rfc/rel-vcs/)
+microformat, and uses it to embed the repository location information in
+every wiki page.
+
+By using this plugin, you will make [[Joey]] very happy, as he will be able
+to easily check out the source of your wiki, for purposes of debugging and
+general curiosity. More generally, making it easy for others to find the
+repository for your wiki is just a Plain Good Idea(TM).
-[[template id=plugin name=rst author="martin f. krafft"]]
-[[tag type/format]]
+[[!template id=plugin name=rst author="martin f. krafft"]]
+[[!tag type/format]]
This plugin lets ikwiki convert files with names ending in ".rst" to html.
It uses the [reStructuredText](http://docutils.sourceforge.net/rst.html)
-markup syntax. You need to have [[cpan RPC::XML]], python and the
+markup syntax. You need to have [[!cpan RPC::XML]], python and the
python-docutils module installed to use it.
Note that this plugin does not interoperate very well with the rest of
* There are issues with inserting raw html into documents, as ikiwiki
does with [[WikiLinks|ikiwiki/WikiLink]] and many
- [[PreprocessorDirectives|ikiwiki/PreprocessorDirective]].
+ [[directives|ikiwiki/directive]].
So while you may find this useful for importing old files into your wiki,
using this as your main markup language in ikiwiki isn't recommended at
* csv directive doesn't require csv.py
* references directive doesn't allow options
-There may be a few others; my eyes glazed over. --Ethan
\ No newline at end of file
+There may be a few others; my eyes glazed over. --Ethan
+
+rst support for ikiwiki seems to be on hold. rst is much more elegant
+than markdown in my opinion, so I tried it out in ikiwiki. I found out
+in other places that some directives work just fine, like [[meta]] and
+[[tag]], others work fine if you wrap them in `.. raw::`, like [[inline]].
+
+But to make a wiki we need [[WikiLinks]]; they can't be escape-inserted or
+such since they are inline elements in the text.. But images work fine in
+rst's syntax.. what about using rst syntax for wikilinks as well?
+Is it possible to inject something into the parser to turn unmached links
+``WikiLink`_` into ikiwiki links? --ulrik
-[[template id=plugin name=search author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=search author="[[Joey]]"]]
+[[!tag type/web]]
This plugin adds full text search to ikiwiki, using the
[xapian](http://xapian.org/) engine, its
[omega](http://xapian.org/docs/omega/overview.html) frontend, and the
-[[cpan Search::Xapian]], [[cpan Digest::SHA1]], and [[cpan HTML::Scrubber]]
+[[!cpan Search::Xapian]], [[!cpan Digest::SHA1]], and [[!cpan HTML::Scrubber]]
perl modules.
The [[ikiwiki/searching]] page describes how to write search queries.
-[[template id=plugin name=shortcut author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=shortcut author="[[Joey]]"]]
+[[!tag type/format]]
-This plugin allows external links to commonly linked to sites to be made
+This plugin provides the [[ikiwiki/directive/shortcut]] [[ikiwiki/directive]].
+It allows external links to commonly linked to sites to be made
more easily using shortcuts.
The available shortcuts are defined on the [[shortcuts]] page in
+The plugin depends on [[mdwn]]. If you have
+disabled [[mdwn]], to get [[shortcut]] work, you need
+commit in a shortcuts.ext (ext is `rcs|creole|html|txt|etc`),
+and edit/patch [[shortcut]].
+
+Maybe use the `default_pageext` is better than hardcode .mdwn?
+
+--[[weakish]]
+
+> done, it will use `default_pageext` now --[[Joey]]
+
-[[template id=plugin name=sidebar author="Tuomo Valkonen"]]
-[[tag type/chrome]]
+[[!template id=plugin name=sidebar author="Tuomo Valkonen"]]
+[[!tag type/chrome]]
If this plugin is enabled, then a sidebar is added to pages in the wiki.
The content of the sidebar is simply the content of a page named
-[[template id=plugin name=signinedit core=1 author="[[Joey]]"]]
-[[tag type/auth]]
+[[!template id=plugin name=signinedit core=1 author="[[Joey]]"]]
+[[!tag type/auth]]
This plugin, which is enabled by default, requires users be logged in
before editing pages in the wiki.
-[[template id=plugin name=smiley author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=smiley author="[[Joey]]"]]
+[[!tag type/chrome]]
This plugin makes it easy to insert smileys and other special symbols into
pages in the wiki. The symbols are all listed on the [[smileys]] page,
-[[template id=plugin name=sparkline author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=sparkline author="[[Joey]]"]]
+[[!tag type/chrome]]
-This plugin allows for easily embedding sparklines into wiki pages. A
-sparkline is a small word-size graphic chart, that is designed to be
-inlined alongside text.
+This plugin provides the [[ikiwiki/directive/sparkline]]
+[[ikiwiki/directive]], which allows for easily embedding sparklines into
+wiki pages. A sparkline is a small word-size graphic chart, that is designed
+to be displayed alongside text.
# requirements
php can find it when `sparkline/Sparkline.php` is required.
* The GD PHP module used by the Sparkline library.
* A "php" program in the path, that can run standalone php programs.
-* [[cpan Digest::SHA1]]
+* [[!cpan Digest::SHA1]]
On a Debian system, this can be accomplished by installing these packages:
`libsparkline-php` `php5-gd` `php5-cli` `libdigest-sha1-perl`
-
-This plugin also uses the [[cpan Digest::SHA1]] perl module.
-
-# examples
-
- \[[sparkline 1 3 5 -3 10 0 width=40 height=16
- featurepoint="4,-3,red,3" featurepoint="5,10,green,3"]]
-
-This creates a simple line graph, graphing several points.
-[[if test="enabled(sparkline)" then="""
-[[sparkline 1 3 5 -3 10 0 width=40 height=16
-featurepoint="4,-3,red,3" featurepoint="5,10,green,3"]]
-"""]]
-It will be drawn 40 pixels wide and 16 pixels high. The high point in the
-line has a green marker, and the low point has a red marker.
-
- \[[sparkline 1 -1(red) 1 -1(red) 1 1 1 -1(red) -1(red) style=bar barwidth=2
- barspacing=1 height=13]]
-
-This more complex example generates a bar graph.
-[[if test="enabled(sparkline)" then="""
-[[sparkline 1 -1(red) 1 -1(red) 1 1 1 -1(red) -1(red)
-style=bar barwidth=2 barspacing=1 height=13]]
-"""]]
-The bars are 2 pixels wide, and separated by one pixel, and the graph is 13
-pixels tall. Width is determined automatically for bar graphs. The points
-with negative values are colored red, instead of the default black.
-
-# usage
-
-The form for the data points is "x,y", or just "y" if the x values don't
-matter. Bar graphs can also add "(color)" to specify a color for that bar.
-
-The following named parameters are recognised. Most of these are the same
-as those used by the underlying sparkline library, which is documented in
-more detail in [its wiki](http://sparkline.wikispaces.com/usage).
-
-* `style` - Either "line" (the default) or "bar".
-* `width` - Width of the graph in pixels. Only needed for line graphs.
-* `height` - Height of the graph in pixels. Defaults to 16.
-* `barwidth` - Width of bars in a bar graph. Default is 1 pixel.
-* `barspacing` - Spacing between bars in a bar graph, in pixels. Default is
- 1 pixel.
-* `ymin`, `ymax` - Minimum and maximum values for the Y axis. This is
- normally calculated automatically, but can be explicitly specified to get
- the same values for multiple related graphs.
-* `featurepoint` - Adds a circular marker to a line graph, with optional
- text. This can be used to label significant points.
-
- The value is a comma-delimited list of parameters specifying the feature
- point: X value, Y value, color name, circle diameter, text (optional),
- and text location (optional). Example: `featurepoint="3,5,blue,3"`
-
- Available values for the text location are: "top", "right", "bottom", and
- "left".
-[[template id=plugin name=table author="[[VictorMoral]]"]]
-[[tag type/format]]
+[[!template id=plugin name=table author="[[VictorMoral]]"]]
+[[!tag type/format]]
-This plugin can build HTML tables from data in CSV (comma-separated values)
+This plugin provides the [[ikiwiki/directive/table]] [[ikiwiki/directive]].
+It can build HTML tables from data in CSV (comma-separated values)
or DSV (delimiter-separated values) format.
-It needs the perl module [[cpan Text::CSV]] for the CSV data.
-
-## examples
-
- \[[table data="""
- Customer|Amount
- Fulanito|134,34
- Menganito|234,56
- Menganito|234,56
- """]]
-
- \[[table class="book_record" format=csv file="data/books/record1"]]
-
-In this second example the `record1` page should be similar to:
-
- "Title","Perl Best Practices"
- "Author","Damian Conway"
- "Publisher","O’Reilly"
-
-To make a cell span multiple columns, follow it with one or more empty
-cells. For example:
-
- \[[table data="""
- left||right|
- a|b|c|d
- this cell spans 4 columns|||
- """]]
-
-## usage
-
-* `data` - Values for the table.
-* `file` - A file in the wiki containing the data.
-* `format` - The format of the data, either "csv", "dsv", or "auto"
- (the default).
-* `delimiter` - The character used to separate fields. By default,
- DSV format uses a pipe (`|`), and CSV uses a comma (`,`).
-* `class` - A CSS class for the table html element.
-* `header` - Set to "no" to make a table without a header. By default,
- the first data line is used as the table header.
+It needs the perl module [[!cpan Text::CSV]] for the CSV data.
Here is the links to the patch and to a patched version of the plugin :
-+ [table.pm.patch](http://lohrun.free.fr/ikiwiki/table.pm.patch)
-+ [table.pm](http://lohrun.free.fr/ikiwiki/table.pm)
++ [table.pm.patch](http://alexandre.dupas.free.fr/code/ikiwiki/table.pm.patch)
++ [table.pm](http://alexandre.dupas.free.fr/code/ikiwiki/table.pm)
I hope this might be intresting for some ikiwiki user's.
--[[AlexandreDupas]]
+
+> Thanks for the patch, I've merged it in.
+> (Just FYI, in future, I recommend using a unified diff. Also, not
+> renaming variables that don't really need to be renamed makes your patch
+> easier to apply.) --[[Joey]]
+
+---
+
+# Horizontal cell alignment
+
+Do you know any easy method of horizontal cell alignment? I know I can set `class`
+attribute for the table, but how to set different `class` for different cells?
+
+[DokuWiki](http://www.dokuwiki.org/) has a nice horizontal alignment solution.
+Suppose that we have `|foo|` cell. If I want to align the cell to left,
+then I should type `|foo |`. If I want to do right alignment, then I type `| foo|`.
+For centering cell content I need to type `| foo |`. Please note that I used
+only one space for all examples, but in DokuWiki I can use many spaces.
+
+Do you like it? Can you implement the same in Ikiwiki? :) --[[Paweł|ptecza]]
+
+> Multimarkdown has [table support](http://fletcherpenney.net/multimarkdown/users_guide/multimarkdown_syntax_guide/#tables)
+> that includes alignment. (Using colons to control it.) So you can turn on
+> `multimarkdown` in setup to use that.
+>
+> I'd not mind if someone adds alignment to this plugin. Although the
+> universe of possible table formatting stuff is nearly endless, and at
+> some point it becomes clearer and simpler to just write the table in
+> html.. --[[Joey]]
+
+>> Thanks a lot for the info about Multimarkdown! It seems very interesting.
+
+>> I'll look at that plugin and try to add that feature, if it's not
+>> too hard.
+
+>> I know that people have many ideas how to format their tables
+>> and it's not easy to create universal tool. Of course `table` plugin
+>> was written rather for simple usage. However cell alignment is very
+>> helpful feature, so I think the plugin should be able to do it.
+>> --[[Paweł|ptecza]]
-[[template id=plugin name=tag author="[[Joey]]"]]
-[[tag type/tags type/link]]
+[[!template id=plugin name=tag author="[[Joey]]"]]
+[[!tag type/tags type/link]]
-This plugin allows tagging pages. List tags as follows:
+This plugin provides the [[ikiwiki/directive/tag]] and
+[[ikiwiki/directive/taglink]] [[directives|ikiwiki/directive]].
+These directives allow tagging pages.
- \[[tag tech life linux]]
+It also provides the `tagged()` [[ikiwiki/PageSpec]], which can be used to
+match pages that are tagged with a specific tag.
-The tags work the same as if you had put a (hidden) [[ikiwiki/WikiLink]] on
-the page for each tag, so you can use a [[ikiwiki/PageSpec]] match all
-pages that are tagged with a given tag, for example. The tags will also
-show up on blog entries and at the bottom of the tagged pages, as well as
-in RSS and Atom feeds.
-
-If you want a visible [[ikiwiki/WikiLink]] along with the tag, use taglink
-instead:
-
- \[[taglink foo]]
- \[[taglink tagged_as_foo|foo]]
-
-This plugin has a configuration option. Set --tagbase=tags and links to tags
-will be located under the specified base page. If ikiwiki is configured
-this way, then the example above actually tags the page with the tags
-tags/tech, tags/life, and tags/linux. This is a useful way to avoid
-having to write the full path to tags, if you want to keep them grouped
-together out of the way.
-
-[[if test="enabled(tag)" then="""
+[[!if test="enabled(tag)" then="""
This wiki has the tag plugin enabled, so you'll see a note below that this
page is tagged with the "tags" tag.
"""]]
-I'd like to modify this plugin such that the tag pages are automatically created and populated with a list of relevant posts. The content of the tag page is simply `"\[[inline pages="link(tag/$tag)"]]`. The tag plugin will have to determine whether a page for the given tag already exists, and if not use that Markdown fragment to generate it.
+I'd like to modify this plugin such that the tag pages are automatically created and populated with a list of relevant posts. The content of the tag page is simply `"\[[!inline pages="link(tag/$tag)"]]`. The tag plugin will have to determine whether a page for the given tag already exists, and if not use that Markdown fragment to generate it.
There are clearly many ways to do this, but any opinions on which is the cleanest?
better" --[[DavidBremner]]
Please make the actual text used a template some way or another. I may want `map` instead of `inline`. --[[madduck]]
+
+
+See [[todo/auto-create tag pages according to a template]]
+
+-- Jeremy Schultz <jeremy.schultz@uleth.ca>
+
-[[template id=plugin name=template author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=template author="[[Joey]]"]]
+[[!tag type/format]]
+This plugin provides the [[ikiwiki/directive/template]] [[ikiwiki/directive]].
With this plugin, you can set up templates, and cause them to be filled out
and inserted into pages in the wiki. It's documented and existing templates
are listed in the [[templates]] page.
-[[template id=plugin name=testpagespec author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=testpagespec author="[[Joey]]"]]
+[[!tag type/useful]]
-This plugin allows testing a [[ikiwiki/PageSpec]] to see if it matches a
+This plugin provides a [[ikiwiki/directive/testpagespec]] [[ikiwiki/directive]].
+The directive allows testing a [[ikiwiki/PageSpec]] to see if it matches a
page, and to see the part that matches, or causes the match to fail.
-
-Example uses:
-
- \[[testpagespec pagespec="foopage and barpage" match="foopage"]]
-
-This will print out something like "no match: barpage does not match
-foopage", highlighting which part of the [[ikiwiki/PageSpec]] is causing
-the match to fail.
-
- \[[testpagespec pagespec="foopage or !bar*" match="barpage"]]
-
-This will print out something like "no match: bar* matches barpage", since
-the part of the [[ikiwiki/PageSpec]] that fails is this negated match.
-
- \[[testpagespec pagespec="foopage or barpage" match="barpage"]]
-
-This will print out something like "match: barpage matches barpage",
-indicating the part of the [[ikiwiki/PageSpec]] that caused it to match.
-[[template id=plugin name=teximg author="[[PatrickWinnertz]]"]]
-[[tag type/chrome type/slow]]
+[[!template id=plugin name=teximg author="[[PatrickWinnertz]]"]]
+[[!tag type/chrome type/slow]]
-This plugin renders LaTeX formulas into images.
+This plugin provides a [[ikiwiki/directive/teximg]] [[ikiwiki/directive]],
+that renders LaTeX formulas into images.
-Of course you will need LaTeX installed for this to work. The plugin
-also uses mhchem.sty, which in Debian is in the texlive-science package and
-may not be part of a regular texlive installation.
+Of course you will need LaTeX installed for this to work.
-## examples
+See [this site](http://www.der-winnie.de/opensource/gsoc2007) for rendered
+images.
- \[[teximg code="\ce{[Cu(NH3)3]^{2+}}"]]
- \[[teximg code="\frac{1}{2}"]]
- \[[teximg code="E = - \frac{Z^2 \cdot \mu \cdot e^4}{32\pi^2 \epsilon_0^2 \hbar^2 n^2}" ]]
+## configuration
-To scale the image, use height=x:
-
- \[[teximg code="\ce{[Cu(NH3)3]^{2+}}" height="17"]]
- \[[teximg code="\ce{[Cu(NH3)3]^{2+}}" height="8"]]
-
-If no height is choosen the default height 12 is used. Valid heights are: 8, 9,
-10, 11, 12, 14, 17, 20. If another height is entered, the closest available
-height is used.
-
-To add an alt text to the image, use alt="text":
-
- \[[teximg code="\frac{1}{2}" alt="1/2"]]
-
-See [this site](http://www.der-winnie.de/opensource/gsoc2007) for rendered images.
+There are several configuration directives that can be used in the setup
+file. `teximg_prefix` can be set to change the LaTeX preamble, and
+`teximg_postfix` to change the LaTeX postfix. The `teximg_dvipng` setting
+can be set to 0 to disable use of `dvipng`, and instead force use of `dvips`
+and `convert`.
-[[template id=plugin name=syntax author="mazirian"]]
-[[tag type/format]]
+[[!template id=plugin name=syntax author="mazirian"]]
+[[!tag type/format]]
Textile is a versatile markup language. So here's a plugin that will use the
Textile markup language to render .txtl files in your data directory.
-You must have [[cpan Text::Textile]] installed for it to work.
+You must have [[!cpan Text::Textile]] installed for it to work.
+++ /dev/null
-.
\ No newline at end of file
-[[template id=plugin name=toc author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=toc author="[[Joey]]"]]
+[[!tag type/chrome]]
-Add a table of contents to a page:
-
- \[[toc ]]
-
-The table of contents will be automatically generated based on the
-headers of the page. By default only the largest headers present on the
-page will be shown; to control how many levels of headers are shown, use
-the `levels` parameter:
-
- \[[toc levels=2]]
-
-The toc plugin will take the level of the first header as the topmost
-level, even if there are higher levels seen later in the file.
-
-The table of contents will be created as an ordered list. If you want
-an unordered list instead, you can change the list-style in your local
-style sheet.
\ No newline at end of file
+This plugin provides the [[ikiwiki/directive/toc]] [[ikiwiki/directive]],
+which adds a table of contents to a page.
-[[template id=plugin name=toggle author="[[Joey]]"]]
-[[tag type/chrome]]
+[[!template id=plugin name=toggle author="[[Joey]]"]]
+[[!tag type/chrome]]
-With this plugin you can create links on pages that, when clicked, toggle
+This plugin provides the [[ikiwiki/directive/toggle]] and
+[[ikiwiki/directive/toggleable]] [[directives|ikiwiki/directive]].
+With these directives you can create links on pages that, when clicked, toggle
display of other parts of the page.
-
-It uses javascript to accomplish this; browsers without javascript will
-always see the full page content.
-
-Example use:
-
- \[[toggle id="ipsum" text="show"]]
-
- \[[toggleable id="ipsum" text="""
- Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
- eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
- ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
- aliquip ex ea commodo consequat.
-
- [[toggle id="ipsum" text="hide"]]
- """]]
-
-Note that you can include wiki markup in the toggleable text,
-including even additional toggles, as shown in the above example.
-
-Also, the toggle and the togglable definitions do not need to be next to
-each other, but can be located anywhere on the page. There can also be
-mutiple toggles that all toggle a single togglable.
-
-The id has a default value of "default", so can be omitted in simple cases.
-
-If you'd like a toggleable to be displayed by default, and toggle to
-hidden, then pass a parameter "open=true" when setting up the toggleable.
## Nested plugins
Is it possible to use another plugin into your toggle plugin? For example,
-I want to have toggleable table and try to use Victor Moral's table plugin,
+I want to have toggleable table and try to use [[Victor Moral|users/victormoral]]'s [[table plugin|plugins/table]],
but no success. How can I do it?
--PTecza
## [[bugs/Bug_when_toggling_in_a_preview_page]]
+
+----
+
+## Using toggle directives in a list item##
+Take this code snippet.
+
+ * [[!toggle id="test" text="test"]]
+ [[!toggleable id="test text="""toggle"""]]
+
+In the HTML-output the `ul` and `div` overlap.
+
+ <div id="content">
+ <ul>
+ <li><a class="toggle" href="#test.test">test</a>
+ <div class="toggleable" id="test.-test"></li>
+ </ul>
+
+ <p>toggle</p>
+
+ </div>
+
+ </div>
+
+Fixing this manually the Javascript seems not to be working and `toggle` is shown unconditionally.
+
+I do not know if this is due to [[shortcomming with nested preprocessor directives|todo/nested_preprocessor_directives]] you mentioned in the beginning of this page. Maybe a note could be added to the main page of the plugin. --Paul
-[[template id=plugin name=txt author="[[Gabriel]]"]]
-[[tag type/format]]
+[[!template id=plugin name=txt author="[[Gabriel]]"]]
+[[!tag type/format]]
This plugin makes ikiwiki treat files with names ending in ".txt"
as wiki pages.
txt files is done; the file contents is displayed to the user as-is,
with html markup characters such as ">" escaped.
-The only exceptions are that [[WikiLinks|WikiLink]] and
-[[PreprocessorDirectives|PreprocessorDirective]] are still expanded by
-ikiwiki, and that, if the [[cpan URI::Find]] perl module is installed, URLs
+The only exceptions are that [[WikiLinks|ikiwiki/WikiLink]] and
+[[directives|ikiwiki/directive]] are still expanded by
+ikiwiki, and that, if the [[!cpan URI::Find]] perl module is installed, URLs
in the txt file are converted to hyperlinks.
--- /dev/null
+I guess the reason I never thought to write this is when I put a .txt file
+in ikiwiki, I'm happy enough to see it copied through unchanged.
+
+I guess the advantage of using this plugin is that you get the page wrapper
+around the preformatted text, and could even inline such a page.
+
+There is not currently a good way to turn off some processing steps for
+some page types. It's either all or nothing. The patch in
+[[todo/format_escape]] might allow a formatter to register its own special
+version of htmllink that didn't do anything, but would that be enough?
+
+--[[Joey]]
+
+[Here](http://www.gmcmanus.org/plaintext.pm) is an alternate approach.
+It encodes entities using a filter hook, before wikilinks are linkified.
+So wikilinks turn up as links.
+It also uses URI::Find to turn URIs into links.
+
+I'm not very familiar with Perl, so this code could be improved.
+
+--Gabriel
+
+I like this approach! It sidesteps the annoying problem, and it actually
+makes the .txt format genuinely wiki-like, by allowing wikilinks and
+preprocessor directices.
+
+The only thing I am not sure about is the conversion of external urls to
+hyperlinks.
+
+Can you please add a copyright/license statemnt to the top of the plugin?
+If you do, I'll add it to ikiwiki. Thanks! --[[Joey]]
+
+> I've added copyright and license (GPLv2 or later). --Gabriel
--- /dev/null
+These plugins control how ikiwiki displays dates.
--- /dev/null
+These plugins enhance the web interface.
-[[template id=plugin name=typography author="[[Roktas]]"]]
-[[tag type/format]]
+[[!template id=plugin name=typography author="[[Roktas]]"]]
+[[!tag type/format]]
This plugin, also known as
[SmartyPants](http://daringfireball.net/projects/smartypants/), translates
plain ASCII punctuation characters into ``smart'' typographic punctuation HTML
-entities. To use it, you need to have the [[cpan Text::Typography]] module
+entities. To use it, you need to have the [[!cpan Text::Typography]] module
installed.
This plugin has a configuration option. To change the attributes,
set `--typographyattributes=whatever`. See the documentation for
-[[cpan Text::Typography]] for available attributes.
+[[!cpan Text::Typography]] for available attributes.
--- /dev/null
+[[!template id=plugin name=underlay author="[[Simon_McVittie|smcv]]"]]
+[[!tag type/useful]]
+
+This plugin adds an `add_underlays` option to the `.setup` file.
+Its value is a list of underlay directories whose content is added to the wiki.
+
+Multiple underlays are normally set up automatically by other plugins (for
+instance, the images used by the [[plugins/smiley]] plugin), but they can also be
+used as a way to pull in external files that you don't want in revision control,
+like photos or software releases.
+
+Directories in `add_underlays` should usually be absolute. If relative, they're
+interpreted as relative to the parent directory of the basewiki underlay, which
+is probably not particularly useful in this context.
-[[template id=plugin name=version author="[[Joey]]"]]
-[[tag type/useful]]
+[[!template id=plugin name=version author="[[Joey]]"]]
+[[!tag type/meta]]
-This plugin allows inserting the version of ikiwiki onto a page.
-
-Whenever ikiwiki is upgraded to a new version, the page will be rebuilt,
-updating the version number.
-
-Use is simple:
-
- \[[version ]]
+This plugin provides the [[ikiwiki/directive/version]]
+[[ikiwiki/directive]], which inserts the current version
+of ikiwiki into a page.
--- /dev/null
+[[!template id=plugin name=websetup core=0 author="[[Joey]]"]]
+[[!tag type/web]]
+
+This plugin allows wiki admins to configure the wiki using a web interface,
+rather than editing the setup file directly. A "Wiki Setup" button is added
+to the admins' preferences page.
+
+Warning: This plugin rewrites your setup file. Any comments or unusual
+things (such as perl code) in the setup file will not be preserved. Also,
+it will only work correctly with new format setup files, as introduced in
+ikiwiki 2.60. Older setup files have a "wrappers" section, which will not
+be properly preserved if this plugin is used.
+
+Most settings can be modified using the web interface. Plugins can be
+enabled and disabled using it too. Some settings are not considered safe
+enough to be manipulated over the web; these are still shown, by default,
+but cannot be modified. To hide them, set `websetup_show_unsafe` to false
+in the setup file. A few settings have too complex a data type to be
+configured via the web.
+
+Plugins that should not be enabled/disabled via the web interface can be
+listed in `websetup_force_plugins` in the setup file.
+
+When the setup is saved, the setup file will be rewritten with the new
+settings, and the wiki will be refreshed, or rebuilt, to make the setip
+changes take effect.
-[[template id=plugin name=wikitext author="[[Joey]]"]]
-[[tag type/format]]
+[[!template id=plugin name=wikitext author="[[Joey]]"]]
+[[!tag type/format]]
This plugin allows ikiwiki to process pages written in the original wiki
-text format. To use it, you need to have the [[cpan Text::WikiFormat]] perl
+text format. To use it, you need to have the [[!cpan Text::WikiFormat]] perl
module installed, enable the plugin, then files with the extention `.wiki`
will be processed as wiki text.
--- /dev/null
+[[!template id=plugin name=wmd author="[[Will]]"]]
+[[!tag type/chrome]]
+
+[WMD](http://wmd-editor.com/) is a What You See Is What You Mean editor for
+[[mdwn]]. This plugin makes WMD be used for editing pages in the wiki.
+
+To use the plugin, you will need to install WMD. Download the [WMD
+source](http://wmd-editor.com/downloads/wmd-1.0.1.zip). In that zip file
+you'll find a few example html files, a readme and `wmd` directory. Create
+a 'wmd' subdirectory in the ikiwiki `underlaydir` directory (ie `sudo mkdir
+/usr/share/ikiwiki/wmd`). Move the `wmd` directory into the directory you
+made. You should now have a `wmd/wmd/wmd.js` file as well as some other
+javascript files and an images directory in the same place.
+
+Note that the WMD plugin does **not** handle ikiwiki directives. For this
+reason the normal `preview` button remains.
it's not really hard. This page is a complete reference to everything a
plugin might want to do. There is also a quick [[tutorial]].
-[[toc levels=2]]
+[[!toc levels=2]]
## Types of plugins
`IkiWiki::Plugin::pagecount` is another simple example. All perl plugins
should `use IkiWiki` to import the ikiwiki plugin interface. It's a good
idea to include the version number of the plugin interface that your plugin
-expects: `use IkiWiki 2.00`.
+expects: `use IkiWiki 3.00`.
An external plugin is an executable program. It can be written in any
language. Its interface to ikiwiki is via XML RPC, which it reads from
Plugins should, when imported, call `hook()` to hook into ikiwiki's
processing. The function uses named parameters, and use varies depending on
-the type of hook being registered -- see below. Note that a plugin can call
-the function more than once to register multiple hooks. All calls to
-`hook()` should be passed a "type" parameter, which gives the type of
-hook, a "id" paramter, which should be a unique string for this plugin, and
-a "call" parameter, which tells what function to call for the hook.
+the type of hook being registered -- see below. A plugin can call
+the function more than once to register multiple hooks.
+
+All calls to `hook()` should be passed a "type" parameter, which gives the
+type of hook, a "id" parameter, which should be a unique string for this
+plugin, and a "call" parameter, which tells what function to call for the
+hook.
An optional "last" parameter, if set to a true value, makes the hook run
-after all other hooks of its type. Useful if the hook depends on some other
-hook being run first.
+after all other hooks of its type, and an optional "first" parameter makes
+it run first. Useful if the hook depends on some other hook being run first.
## Types of hooks
This allows a plugin to manipulate the list of files that need to be
built when the wiki is refreshed. The function is passed a reference to an
-array of pages that will be rebuilt, and can modify the array, either
+array of files that will be rebuilt, and can modify the array, either
adding or removing files from it.
+### scan
+
+ hook(type => "scan", id => "foo", call => \&scan);
+
+This hook is called early in the process of building the wiki, and is used
+as a first pass scan of the page, to collect metadata about the page. It's
+mostly used to scan the page for [[WikiLinks|ikiwiki/WikiLink]], and add
+them to `%links`. Present in IkiWiki 2.40 and later.
+
+The function is passed named parameters "page" and "content". Its return
+value is ignored.
+
### filter
hook(type => "filter", id => "foo", call => \&filter);
### preprocess
-Adding a [[ikiwiki/PreProcessorDirective]] is probably the most common use
+Adding a preprocessor [[ikiwiki/directive]] is probably the most common use
of a plugin.
hook(type => "preprocess", id => "foo", call => \&preprocess);
-Replace "foo" with the command name that will be used inside brackets for
-the preprocessor directive.
-
-Each time the directive is processed, the referenced function (`preprocess`
-in the example above) is called, and is passed named parameters. A "page"
-parameter gives the name of the page that embedded the preprocessor
-directive, while a "destpage" parameter gives the name of the page the
-content is going to (different for inlined pages), and a "preview"
-parameter is set to a true value if the page is being previewed. All
-parameters included in the directive are included as named parameters as
-well. Whatever the function returns goes onto the page in place of the
+Replace "foo" with the command name that will be used for the preprocessor
directive.
-An optional "scan" parameter, if set to a true value, makes the hook be
-called during the preliminary scan that ikiwiki makes of updated pages,
-before begining to render pages. This parameter should be set to true if
-the hook modifies data in `%links`. Note that doing so will make the hook
-be run twice per page build, so avoid doing it for expensive hooks. (As an
-optimisation, if your preprocessor hook is called in a void contets, you
-can assume it's being run in scan mode.)
+Each time the directive is processed, the referenced function (`preprocess`
+in the example above) is called. Whatever the function returns goes onto
+the page in place of the directive. Or, if the function aborts using
+`error()`, the directive will be replaced with the error message.
+
+The function is passed named parameters. First come the parameters set
+in the preprocessor directive. These are passed in the same order as
+they're in the directive, and if the preprocessor directive contains a bare
+parameter (example: `\[[!foo param]]`), that parameter will be passed with
+an empty value.
+
+After the parameters from the preprocessor directive some additional ones
+are passed: A "page" parameter gives the name of the page that embedded the
+preprocessor directive, while a "destpage" parameter gives the name of the
+page the content is going to (different for inlined pages), and a "preview"
+parameter is set to a true value if the page is being previewed.
+
+If `hook` is passed an optional "scan" parameter, set to a true value, this
+makes the hook be called during the preliminary scan that ikiwiki makes of
+updated pages, before begining to render pages. This should be done if the
+hook modifies data in `%links` (typically by calling `add_link`). Note that
+doing so will make the hook be run twice per page build, so avoid doing it
+for expensive hooks. (As an optimisation, if your preprocessor hook is
+called in a void context, you can assume it's being run in scan mode, and
+avoid doing expensive things at that point.)
Note that if the [[htmlscrubber]] is enabled, html in
-[[ikiwiki/PreProcessorDirective]] output is sanitised, which may limit what
+preprocessor [[ikiwiki/directive]] output is sanitised, which may limit what
your plugin can do. Also, the rest of the page content is not in html
format at preprocessor time. Text output by a preprocessor directive will
be linkified and passed through markdown (or whatever engine is used to
hook(type => "linkify", id => "foo", call => \&linkify);
-This hook is called to convert [[WikiLinks|WikiLink]] on the page into html
+This hook is called to convert [[WikiLinks|ikiwiki/WikiLink]] on the page into html
links. The function is passed named parameters "page", "destpage", and
"content". It should return the linkified content. Present in IkiWiki 2.40
and later.
Plugins that implement linkify must also implement a scan hook, that scans
-for the links on the page and adds them to `%links`.
-
-### scan
-
- hook(type => "scan", id => "foo", call => \&scan);
-
-This hook is called early in the process of building the wiki, and is used
-as a first pass scan of the page, to collect metadata about the page. It's
-mostly used to scan the page for WikiLinks, and add them to `%links`.
-Present in IkiWiki 2.40 and later.
-
-The function is passed named parameters "page" and "content". Its return
-value is ignored.
+for the links on the page and adds them to `%links` (typically by calling
+`add_link`).
### htmlize
hook(type => "htmlize", id => "ext", call => \&htmlize);
-Runs on the raw source of a page and turns it into html. The id parameter
+Runs on the source of a page and turns it into html. The id parameter
specifies the filename extension that a file must have to be htmlized using
this plugin. This is how you can add support for new and exciting markup
languages to ikiwiki.
The function is passed named parameters: "page" and "content" and should
return the htmlized content.
+If `hook` is passed an optional "keepextension" parameter, set to a true
+value, then the extension will not be stripped from the source filename when
+generating the page.
+
+If `hook` is passed an optional "noextension" parameter, set to a true
+value, then the id parameter specifies not a filename extension, but
+a whole filename that can be htmlized. This is useful for files
+like `Makefile` that have no extension.
+
+If `hook` is passed an optional "longname" parameter, this value is used
+when prompting a user to choose a page type on the edit page form.
+
### pagetemplate
hook(type => "pagetemplate", id => "foo", call => \&pagetemplate);
a cgi. This hook allows modifying the variables available on those
templates. The function is passed named parameters. The "page" and
"destpage" parameters are the same as for a preprocess hook. The "template"
-parameter is a [[cpan HTML::Template]] object that is the template that
+parameter is a [[!cpan HTML::Template]] object that is the template that
will be used to generate the page. The function can manipulate that
template object.
The function is passed named parameters: "page", "destpage", and "content",
and should return the sanitized content.
+### postscan
+
+ hook(type => "postscan", id => "foo", call => \&postscan);
+
+This hook is called once the full page body is available (but before the
+format hook). The most common use is to update search indexes. Added in
+ikiwiki 2.54.
+
+The function is passed named parameters "page" and "content". Its return
+value is ignored.
+
### format
hook(type => "format", id => "foo", call => \&format);
hook(type => "auth", id => "foo", call => \&auth);
-This hook can be used to implement a different authentication method than
-the standard web form. When a user needs to be authenticated, each registered
-auth hook is called in turn, and passed a CGI object and a session object.
+This hook can be used to implement an authentication method. When a user
+needs to be authenticated, each registered auth hook is called in turn, and
+passed a CGI object and a session object.
If the hook is able to authenticate the user, it should set the session
object's "name" parameter to the authenticated user's name. Note that
### canedit
- hook(type => "canedit", id => "foo", call => \&pagelocked);
+ hook(type => "canedit", id => "foo", call => \&canedit);
This hook can be used to implement arbitrary access methods to control when
a page can be edited using the web interface (commits from revision control
since it's sometimes used to test to see which pages in a set of pages a
user can edit.
+### canremove
+
+ hook(type => "canremove", id => "foo", call => \&canremove);
+
+This hook can be used to implement arbitrary access methods to control
+when a page can be removed using the web interface (commits from
+revision control bypass it). It works exactly like the `canedit` hook,
+but is passed the named parameters `cgi` (a CGI object), `session`
+(a session object) and `page` (the page subject to deletion).
+
+### canrename
+
+ hook(type => "canrename", id => "foo", call => \&canrename);
+
+This hook can be used to implement arbitrary access methods to control when
+a page can be renamed using the web interface (commits from revision control
+bypass it). It works exactly like the `canedit` hook,
+but is passed the named parameters `cgi` (a CGI object), `session` (a
+session object), `src`, `srcfile`, `dest` and `destfile`.
+
+### checkcontent
+
+ hook(type => "checkcontent", id => "foo", call => \&checkcontent);
+
+This hook is called to check the content a user has entered on a page,
+before it is saved, and decide if it should be allowed.
+
+It is passed named parameters: `content`, `page`, `cgi`, and `session`. If
+the content the user has entered is a comment, it may also be passed some
+additional parameters: `author`, `url`, and `subject`. The `subject`
+parameter may also be filled with the user's comment about the change.
+
+Note: When the user edits an existing wiki page, this hook is also
+passed a `diff` named parameter, which will include only the lines
+that they added to the page, or modified.
+
+The hook should return `undef` on success. If the content is disallowed, it
+should return a message stating what the problem is, or a function
+that can be run to perform whatever action is necessary to allow the user
+to post the content.
+
### editcontent
hook(type => "editcontent", id => "foo", call => \&editcontent);
hook(type => "formbuilder_setup", id => "foo", call => \&formbuilder_setup);
hook(type => "formbuilder", id => "foo", call => \&formbuilder);
-These hooks allow tapping into the parts of ikiwiki that use [[cpan
+These hooks allow tapping into the parts of ikiwiki that use [[!cpan
CGI::FormBuilder]] to generate web forms. These hooks are passed named
parameters: `cgi`, `session`, `form`, and `buttons`. These are, respectively,
the `CGI` object, the user's `CGI::Session`, a `CGI::FormBuilder`, and a
hook(type => "savestate", id => "foo", call => \&savestate);
-This hook is called wheneven ikiwiki normally saves its state, just before
+This hook is called whenever ikiwiki normally saves its state, just before
the state is saved. The function can save other state, modify values before
they're saved, etc.
+### renamepage
+
+ hook(type => "renamepage", id => "foo", call => \&renamepage);
+
+This hook is called by the [[plugins/rename]] plugin when it renames
+something, once per page linking to the renamed page's old location.
+The hook is passed named parameters: `page`, `oldpage`, `newpage`, and
+`content`, and should try to modify the content of `page` to reflect
+the name change. For example, by converting links to point to the
+new page.
+
+### rename
+
+ hook(type => "rename", id => "foo", call => \&rename);
+
+When a page or set of pages is renamed, the referenced function is
+called for every page, and is passed named parameters:
+
+* `torename`: a reference to a hash with keys: `src`, `srcfile`,
+ `dest`, `destfile`, `required`.
+* `cgi`: a CGI object
+* `session`: a session object.
+
+Such a hook function returns any additional rename hashes it wants to
+add. This hook is applied recursively to returned additional rename
+hashes, so that it handles the case where two plugins use the hook:
+plugin A would see when plugin B adds a new file to be renamed.
+
+### getsetup
+
+ hook(type => "getsetup", id => "foo", call => \&getsetup);
+
+This hooks is not called during normal operation, but only when setting up
+the wiki, or generating a setup file. Plugins can use this hook to add
+configuration options.
+
+The hook is passed no parameters. It returns data about the configuration
+options added by the plugin. It can also check if the plugin is usable, and
+die if not, which will cause the plugin to not be offered in the configuration
+interface.
+
+The data returned is a list of `%config` options, followed by a hash
+describing the option. There can also be an item named "plugin", which
+describes the plugin as a whole. For example:
+
+ return
+ option_foo => {
+ type => "boolean",
+ description => "enable foo?",
+ advanced => 1,
+ safe => 1,
+ rebuild => 1,
+ },
+ option_bar => {
+ type => "string",
+ example => "hello",
+ description => "option bar",
+ safe => 1,
+ rebuild => 0,
+ },
+ plugin => {
+ description => "description of this plugin",
+ safe => 1,
+ rebuild => 1,
+ },
+
+* `type` can be "boolean", "string", "integer", "pagespec",
+ or "internal" (used for values that are not user-visible). The type is
+ the type of the leaf values; the `%config` option may be an array or
+ hash of these.
+* `example` can be set to an example value.
+* `description` is a short description of the option.
+* `link` is a link to further information about the option. This can either
+ be a [[ikiwiki/WikiLink]], or an url.
+* `advanced` can be set to true if the option is more suitable for advanced
+ users.
+* `safe` should be false if the option should not be displayed in unsafe
+ configuration methods, such as the web interface. Anything that specifies
+ a command to run, a path on disk, or a regexp should be marked as unsafe.
+ If a plugin is marked as unsafe, that prevents it from being
+ enabled/disabled.
+* `rebuild` should be true if changing the option (or enabling/disabling
+ the plugin) will require a wiki rebuild, false if no rebuild is needed,
+ and undef if a rebuild could be needed in some circumstances, but is not
+ strictly required.
+
## Plugin interface
To import the ikiwiki plugin interface:
- use IkiWiki '1.00';
+ use IkiWiki '3.00';
This will import several variables and functions into your plugin's
namespace. These variables and functions are the ones most plugins need,
A plugin can access the wiki's configuration via the `%config`
hash. The best way to understand the contents of the hash is to look at
-[[ikiwiki.setup]], which sets the hash content to configure the wiki.
+your ikiwiki setup file, which sets the hash content to configure the wiki.
### %pagestate
The `%pagestate` hash can be used by plugins to save state that they will need
next time ikiwiki is run. The hash holds per-page state, so to set a value,
-use `%pagestate{$page}{$id}{$key}=$value`, and to retrieve the value,
-use `%pagestate{$page}{$id}{$key}`.
+use `$pagestate{$page}{$id}{$key}=$value`, and to retrieve the value,
+use `$pagestate{$page}{$id}{$key}`.
The `$value` can be anything that perl's Storable module is capable of
serializing. `$key` can be any string you like, but `$id` must be the same
Note that page state does not persist across wiki rebuilds, only across
wiki updates.
+### %wikistate
+
+The `%wikistate` hash can be used by a plugin to store persistant state
+that is not bound to any one page. To set a value, use
+`$wikistate{$id}{$key}=$value, where `$value` is anything Storable can
+serialize, `$key` is any string you like, and `$id` must be the same as the
+"id" parameter passed to `hook()` when registering the plugin, so that the
+state can be dropped if the plugin is no longer used.
+
### Other variables
If your plugin needs to access data about other pages in the wiki. It can
destination file.
* `%pagesources` contains the name of the source file for each page.
-Also, the %IkiWiki::version variable contains the version number for the
+Also, the `%IkiWiki::version` variable contains the version number for the
ikiwiki program.
### Library functions
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, 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 preprocessor [[ikiwiki/directive]] 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($;@)`
-Creates and returns a [[cpan HTML::Template]] object. The first parameter
+Creates and returns a [[!cpan HTML::Template]] object. The first parameter
is the name of the file in the template directory. The optional remaining
parameters are passed to `HTML::Template->new`.
Passed a page name, returns the base name that will be used for a the html
page created from it. (Ie, it appends ".html".)
+Use this when constructing the filename of a html file. Use `urlto` when
+generating a link to a page.
+
#### `add_depends($$)`
Makes the specified page depend on the specified [[ikiwiki/PageSpec]].
PageSpec should match against. If not passed, relative PageSpecs will match
relative to the top of the wiki.
+#### `pagespec_match_list($$;@)`
+
+Passed a reference to a list of page names, and [[ikiwiki/PageSpec]],
+returns the set of pages that match the [[ikiwiki/PageSpec]].
+
+Additional named parameters can be passed, to further limit the match.
+The most often used is "location", which specifies the location the
+PageSpec should match against. If not passed, relative PageSpecs will match
+relative to the top of the wiki.
+
+Unlike pagespec_match, this may throw an error if there is an error in
+the pagespec.
+
#### `bestlink($$)`
Given a page and the text of a link on the page, determine which
Many plugins need to generate html links and add them to a page. This is
done by using the `htmllink` function. The usual way to call
-`htmlllink` is:
+`htmllink` is:
htmllink($page, $page, $link)
If the destination directory doesn't exist, it will first be created.
+The filename and directory are separate parameters because of
+some security checks done to avoid symlink attacks. Before writing a file,
+it checks to make sure there's not a symlink with its name, to avoid
+following the symlink. If the filename parameter includes a subdirectory
+to put the file in, it also checks if that subdirectory is a symlink, etc.
+The directory parameter, however, is not checked for symlinks. So,
+generally the directory parameter is a trusted toplevel directory like
+the srcdir or destdir, and any subdirectories of this are included in the
+filename parameter.
+
#### `will_render($$)`
Given a page name and a destination file name (not including the base
Given the name of a source file, returns the name of the wiki page
that corresponds to that file.
+#### `pagetitle($)`
+
+Give the name of a wiki page, returns a version suitable to be displayed as
+the page's title. This is accomplished by de-escaping escaped characters in
+the page name. "_" is replaced with a space, and '__NN__' is replaced by
+the UTF character with code NN.
+
+#### `titlepage($)`
+
+This performs the inverse of `pagetitle`, ie, it converts a page title into
+a wiki page name.
+
+#### `linkpage($)`
+
+This converts text that could have been entered by the user as a
+[[ikiwiki/WikiLink]] into a wiki page name.
+
#### `srcfile($;$)`
Given the name of a source file in the wiki, searches for the file in
This is the standard gettext function, although slightly optimised.
-#### `urlto($$)`
+#### `urlto($$;$)`
Construct a relative url to the first parameter from the page named by the
second. The first parameter can be either a page name, or some other
destination file, as registered by `will_render`.
-#### `targetpage($$)`
+If the third parameter is passed and is true, an absolute url will be
+constructed instead of the default relative url.
+
+#### `newpagefile($$)`
+
+This can be called when creating a new page, to determine what filename
+to save the page to. It's passed a page name, and its type, and returns
+the name of the file to create, relative to the srcdir.
+
+#### `targetpage($$;$)`
Passed a page and an extension, returns the filename that page will be
rendered to.
-## Internal use pages
+Optionally, a third parameter can be passed, to specify the preferred
+filename of the page. For example, `targetpage("foo", "rss", "feed")`
+will yield something like `foo/feed.rss`.
+
+#### `add_link($$)`
+
+This adds a link to `%links`, ensuring that duplicate links are not
+added. Pass it the page that contains the link, and the link text.
+
+## Miscellaneous
+
+### Internal use pages
Sometimes it's useful to put pages in the wiki without the overhead of
having them be rendered to individual html files. Such internal use pages
To make an internal use page, register a filename extension that starts
with "_". Internal use pages cannot be edited with the web interface,
-generally shouldn't contain wikilinks or preprocessor directives (use
+generally shouldn't contain [[WikiLinks|ikiwiki/WikiLink]] or preprocessor directives (use
either on them with extreme caution), and are not matched by regular
PageSpecs glob patterns, but instead only by a special `internal()`
[[ikiwiki/PageSpec]].
-## RCS plugins
+### RCS plugins
+
+ikiwiki's support for [[revision_control_systems|rcs]] is also done via
+plugins. See [[RCS_details|rcs/details]] for some more info.
+
+RCS plugins must register a number of hooks. Each hook has type 'rcs',
+and the 'id' field is set to the name of the hook. For example:
+
+ hook(type => "rcs", id => "rcs_update", call => \&rcs_update);
+ hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit);
+
+#### `rcs_update()`
+
+Updates the working directory with any remote changes.
+
+#### `rcs_prepedit($)`
+
+Is passed a file to prepare to edit. It can generate and return an arbitrary
+token, that will be passed into `rcs_commit` when committing. For example,
+it might return the current revision ID of the file, and use that
+information later when merging changes.
+
+#### `rcs_commit($$$;$$)`
+
+Passed a file, message, token (from `rcs_prepedit`), user, and ip address.
+Should try to commit the file. Returns `undef` on *success* and a version
+of the page with the rcs's conflict markers on failure.
+
+#### `rcs_commit_staged($$$)`
+
+Passed a message, user, and ip address. Should commit all staged changes.
+Returns undef on success, and an error message on failure.
+
+Changes can be staged by calls to `rcs_add`, `rcs_remove`, and
+`rcs_rename`.
+
+#### `rcs_add($)`
+
+Adds the passed file to the archive. The filename is relative to the root
+of the srcdir.
+
+Note that this should not commit the new file, it should only
+prepare for it to be committed when rcs_commit (or `rcs_commit_staged`) is
+called. Note that the file may be in a new subdir that is not yet in
+to version control; the subdir can be added if so.
+
+#### `rcs_remove($)`
+
+Remove a file. The filename is relative to the root of the srcdir.
+
+Note that this should not commit the removal, it should only prepare for it
+to be committed when `rcs_commit` (or `rcs_commit_staged`) is called. Note
+that the new file may be in a new subdir that is not yet in version
+control; the subdir can be added if so.
+
+#### `rcs_rename($$)`
+
+Rename a file. The filenames are relative to the root of the srcdir.
+
+Note that this should not commit the rename, it should only
+prepare it for when `rcs_commit` (or `rcs_commit_staged`) is called.
+The new filename may be in a new subdir, that is not yet added to
+version control. If so, the subdir will exist already, and should
+be added to revision control.
+
+#### `rcs_recentchanges($)`
+
+Examine the RCS history and generate a list of recent changes.
+The parameter is how many changes to return.
+
+The data structure returned for each change is:
+
+ {
+ rev => # the RCSs id for this commit
+ user => # name of user who made the change,
+ committype => # either "web" or the name of the rcs,
+ when => # time when the change was made,
+ message => [
+ { line => "commit message line 1" },
+ { line => "commit message line 2" },
+ # etc,
+ ],
+ pages => [
+ {
+ page => # name of page changed,
+ diffurl => # optional url to a diff of changes
+ },
+ # repeat for each page changed in this commit,
+ ],
+ }
+
+#### `rcs_diff($)`
+
+The parameter is the rev from `rcs_recentchanges`.
+Should return a list of lines of the diff (including \n) in list
+context, and the whole diff in scalar context.
+
+#### `rcs_getctime($)`
-ikiwiki's support for [[revision_control_systems|rcs]] also uses pluggable
-perl modules. These are in the `IkiWiki::RCS` namespace, for example
-`IkiWiki::RCS::svn`.
+This is used to get the page creation time for a file from the RCS, by looking
+it up in the history.
-Each RCS plugin must support all the `IkiWiki::rcs_*` functions.
-See IkiWiki::RCS::Stub for the full list of functions. It's ok if
-`rcs_getctime` does nothing except for throwing an error.
+It's ok if this is not implemented, and throws an error.
-See [[RCS_details|rcs/details]] for some more info.
+#### `rcs_receive()`
-## PageSpec plugins
+This is called when ikiwiki is running as a pre-receive hook (or
+equivalent), and is testing if changes pushed into the RCS from an
+untrusted user should be accepted. This is optional, and doesn't make
+sense to implement for all RCSs.
+
+It should examine the incoming changes, and do any sanity
+checks that are appropriate for the RCS to limit changes to safe file adds,
+removes, and changes. If something bad is found, it should exit
+nonzero, to abort the push. Otherwise, it should return a list of
+files that were changed, in the form:
+
+ {
+ file => # name of file that was changed
+ action => # either "add", "change", or "remove"
+ path => # temp file containing the new file content, only
+ # needed for "add"/"change", and only if the file
+ # is an attachment, not a page
+ }
+
+The list will then be checked to make sure that each change is one that
+is allowed to be made via the web interface.
+
+### PageSpec plugins
It's also possible to write plugins that add new functions to
[[PageSpecs|ikiwiki/PageSpec]]. Such a plugin should add a function to the
IkiWiki::PageSpec package, that is named `match_foo`, where "foo()" is
how it will be accessed in a [[ikiwiki/PageSpec]]. The function will be passed
two parameters: The name of the page being matched, and the thing to match
-against. It may also be passed additional, named parameters. It should return
-a IkiWiki::SuccessReason object if the match succeeds, or an
-IkiWiki::FailReason object if the match fails.
+against. It may also be passed additional, named parameters.
+
+It should return a IkiWiki::SuccessReason object if the match succeeds, or
+an IkiWiki::FailReason object if the match fails. If the match cannot be
+attempted at all, for any page, it can instead return an
+IkiWiki::ErrorReason object explaining why.
+
+### Setup plugins
+
+The ikiwiki setup file is loaded using a pluggable mechanism. If you look
+at the top of a setup file, it starts with 'use IkiWiki::Setup::Standard',
+and the rest of the file is passed to that module's import method.
+
+It's possible to write other modules in the `IkiWiki::Setup::` namespace that
+can be used to configure ikiwiki in different ways. These modules should,
+when imported, populate `$IkiWiki::Setup::raw_setup` with a reference
+to a hash containing all the config items. They should also implement a
+`gendump` function.
+
+By the way, to parse a ikiwiki setup file and populate `%config`, a
+program just needs to do something like:
+`use IkiWiki::Setup; IkiWiki::Setup::load($filename)`
+
+### Function overriding
+
+Sometimes using ikiwiki's pre-defined hooks is not enough. Your plugin
+may need to replace one of ikiwiki's own functions with a modified version,
+or wrap one of the functions.
+
+For example, your plugin might want to override `displaytime`, to change
+the html markup used when displaying a date. Or it might want to override
+`IkiWiki::formattime`, to change how a date is formatted. Or perhaps you
+want to override `bestlink` and change how ikiwiki deals with [[WikiLinks|ikiwiki/WikiLink]].
+
+By venturing into this territory, your plugin is becoming tightly tied to
+ikiwiki's internals. And it might break if those internals change. But
+don't let that stop you, if you're brave.
+
+Ikiwiki provides an `inject()` function, that is a powerful way to replace
+any function with one of your own. This even allows you to inject a
+replacement for an exported function, like `bestlink`. Everything that
+imports that function will get your version instead. Pass it the name of
+the function to replace, and a new function to call.
+
+For example, here's how to replace `displaytime` with a version using HTML 5
+markup:
+
+ inject(name => 'IkiWiki::displaytime', call => sub {
+ return "<time>".formattime(@_)."</time>";
+ });
+
+Here's how to wrap `bestlink` with a version that tries to handle
+plural words:
+
+ my $origbestlink=\&bestlink;
+ inject(name => 'IkiWiki::bestlink', call => \&mybestlink);
+
+ sub deplural ($) {
+ my $word=shift;
+ $word =~ s/e?s$//; # just an example :-)
+ return $word;
+ }
+
+ sub mybestlink ($$) {
+ my $page=shift;
+ my $link=shift;
+ my $ret=$origbestlink->($page, $link);
+ if (! length $ret) {
+ $ret=$origbestlink->($page, deplural($link));
+ }
+ return $ret;
+ }
+
+### Javascript
+
+Some plugins use javascript to make ikiwiki look a bit more web-2.0-ish.
+
+All javascript code should be put in `.js` files in the `javascript`
+underlay, and plugins using those files can enable use of the underlay by
+calling `add_underlay("javascript");` in their `import` function.
+
+You'll have to arrange for `<script>` tags to be added to the pages that
+use your javascript. This can be done using a `format` hook.
+
+Ikiwiki provides some utility functions in `ikiwiki.js`, for use by other
+javascript code. These include:
+
+#### `getElementsByClass(cls, node, tag)`
+
+Returns an array of elements with the given class. The node and tag are
+optional and define what document node and element names to search.
+
+#### `hook(name, call)`
+
+The function `call` will be run as part of the hook named `name`.
+
+Note that to hook into `window.onload`, you can use the `onload' hook.
+
+#### `run_hooks(name)`
+
+Runs the hooks with the specified name.
--- /dev/null
+Maybe this is obvious, but the config variable lives in the IkiWiki module, and one probably
+wants to call defaultconfig for most applications.
+<pre>
+%IkiWiki::config=IkiWiki::defaultconfig();
+IkiWiki::Setup::load($config_file);
+print join(",",keys %IkiWiki::config);
+</pre>
+
+[[DavidBremner]]
+
+I'm a little concerned about one aspect of the `%wikistate` variable that was just introduced.
+I think global state for each plugin is a fine idea, but I worry about making it persist across
+rebuilds. (And by rebuild, I assume we're talking about the `--rebuild` option.)
+
+My reasoning is that a 'rebuild' should be similar to checking out a new copy of the wiki
+and building. Another way of saying this is that all permanent state should be in the RCS.
+It is great that there is temporary state stored in other places - I think of it as indexing
+and caching. I'm worried that with the persistence, plugin writers will start putting data
+there that isn't backed by the RCS and that will break IkiWiki's great abilities as a
+distributed wiki.
+
+[[Will]]
+
+> Well, if you look at state that already persists across rebuilds, we have
+> pagectime, which can be extracted from RCS only very slowly in many
+> cases. There's also the separate state stored by the aggregate plugin,
+> which is indeed independant of the RCS, and can in some cases not be
+> replecated by rebuilding a different checkout (if the data is gone from
+> the feeds). Then there's the session cookie database, and the user
+> database, which started out with a lot of local state, has been
+> whittled down by removing admin prefs and subscriptions, but still has
+> important state including password hashes.
+>
+> So while I take your point about the potential for abuse,
+> there's certianly legitimate reasons to need to store data across
+> rebuilds. And plugins have always been able to drop their own files in
+> wikistatedir as aggregate does and have it persist, so the abuse
+> potential has always been there, the barrier has been lowered only
+> slightly.
+>
+> OTOH, if something can be added to the documentation that encourages
+> good behavior, that'd be a good thing ... --[[Joey]]
+
+---
+
+I would find this page clearer split up into sub-pages. Does anyone agree/disagree? -- [[users/Jon]]
External plugins are standalone, executable programs, that can be written
in any language. When ikiwiki starts up, it runs the program, and
-communicates with it using XML RPC. If you want to [[write]] an external
+communicates with it using [XML RPC][xmlrpc]. If you want to [[write]] an external
plugin, read on..
+[xmlrpc]: http://www.xmlrpc.com/
+
ikiwiki contains one sample external plugin, named `externaldemo`. This is
written in perl, but is intended to be an example of how to write an
external plugin in your favorite programming language. Wow us at how much
There's now a second external plugin, the [[rst]] plugin, written in
python. It uses a `proxy.py`, a helper library for ikiwiki python plugins.
-[[toc ]]
+[[!toc ]]
## How external plugins use XML RPC
stdout, also using XML RPC. After reading a command, and before returning
the result, the plugin can output XML RPC requests of its own, calling
functions in ikiwiki. Note: *Never* make an XML RPC request at any other
-time. Ikiwiki won't be listening for it, and you will deadlock.
+time. IkiWiki won't be listening for it, and you will deadlock.
When ikiwiki starts up an external plugin, the first RPC it will make
is to call the plugin's `import()` function. That function typically makes
## Accessing data structures
-Ikiwiki has a few global data structures such as `%config`, which holds
+IkiWiki has a few global data structures such as `%config`, which holds
its configuration. External plugins can use the `getvar` and `setvar` RPCs
to access any such global hash. To get the "url" configuration value,
call `getvar("config", "url")`. To set it, call
XML RPC has a limitation that it does not have a way to pass
undef/NULL/None. There is an extension to the protocol that supports this,
-but it is not yet available in the [[cpan XML::RPC]] library used by
+but it is not yet available in the [[!cpan XML::RPC]] library used by
ikiwiki.
Until the extension is available, ikiwiki allows undef to be communicated
## Function injection
-Some parts of ikiwiki are extensible by adding functions. For example, the
-RCS interface relies on plugins providing several IkiWiki::rcs_* functions.
+Some parts of ikiwiki are extensible by adding or overriding functions.
It's actually possible to do this from an external plugin too.
-To make your external plugin provide an `IkiWiki::rcs_update` function, for
+To make your external plugin override the `IkiWiki::formattime` function, for
example, make an RPC call to `inject`. Pass it named parameters "name" and
"call", where "name" is the name of the function to inject into perl (here
-"Ikiwiki::rcs_update" and "call" is the RPC call ikiwiki will make whenever
+"Ikiwiki::formattime" and "call" is the RPC call ikiwiki will make whenever
that function is run.
If the RPC call is memoizable, you can also pass a "memoize" parameter, set
are called generally rarely, and pass around minimal data.
External plugins should avoid making RPC calls unnecessarily (ie, in a loop).
-Memoizing the results of appropriate RPC calls is one good way to minimise the
+Memoizing the results of appropriate RPC calls is one good way to minimize the
number of calls.
Injecting a replacement for a commonly called ikiwiki function
could result in a lot more RPC calls than expected and slow
-eveything down. `pagetitle`, for instance, is called about 100 times
+everything down. `pagetitle`, for instance, is called about 100 times
per page build. Whenever possible, you should tell ikiwiki to memoize
injected functions.
sequence. To output the next number in the sequence, all a user has to do
is write this on a wiki page:
- [[fib ]]
+ \[[!fib]]
-When the page is built, the [[ikiwiki/PreProcessorDirective]] will be
+When the page is built, the [[ikiwiki/directive]] will be
replaced by the next number in the sequence.
Most of ikiwiki's plugins are written in Perl, and it's currently easiest
use warnings;
use strict;
- use IkiWiki 2.00;
+ use IkiWiki 3.00;
Ok, boilerplate is out of the way. Now to add the one function that ikiwiki
expects to find in any module: `import`. The import function is called when
}
This has hooked our plugin into the preprocess hook, which ikiwiki uses to
-expand [[PreprocessorDirectives|ikiwiki/preprocessordirective]]. Notice
+expand preprocessor [[directives|ikiwiki/directive]]. Notice
that "fib" has shown up again. It doesn't actually have to match the module
name this time, but it generally will. This "fib" is telling ikiwiki what
-kind of PreprocessorDirective to handle, namely one that looks like this:
+kind of preprocessor directive to handle, namely one that looks like this:
- [[fib ]]
+ [[!fib ]]
Notice the `\&preprocess`? This is how you pass a reference to a function,
and the `preprocess` function is the one that ikiwiki will call to expand
-the PreprocessorDirective. So, time to write that function:
+the preprocessor directive. So, time to write that function:
sub preprocess {
my %params=@_;
Feel free to try it out with a simple page like this:
- [[fib ]], [[fib ]], [[fib ]], [[fib ]], [[fib ]]
+ [[!fib ]], [[!fib ]], [[!fib ]], [[!fib ]], [[!fib ]]
Looks like it works ok, doesn't it? That creates a page that lists:
and the standalone page another. The numbers might even skip over part of
the sequence in some cases.
-Obviously, using a global `$last` veriable was a bad idea. It would
+Obviously, using a global `$last` variable was a bad idea. It would
work ok in a more regular cgi-based wiki, which only outputs one page per
run. But since ikiwiki is a wiki *compiler*, things are a bit more
complicated. It's not very hard to fix, though, if we do want the sequence
It would be nice to be able to jump directly to a given point in the
sequence:
- \[[fib seed=20]], [[fib ]], [[fib ]]
+ \[[!fib seed=20]], [[!fib ]], [[!fib ]]
Just insert these lines of code inside `preprocess`, in the appropriate
spot:
}
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);
}
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
> 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
+
+> Yes, ikiwiki does expect you to use your revision control system to check
+> in changes. Otherwise, recentchanges cannot work right, since it uses the
+> commit history from your revision control system. --[[Joey]]
+
+-----
+
+I'm working on an [[rcs]] plugin for CVS, adapted from `svn.pm`, in order
+to integrate ikiwiki at sites where that's all they've got. What's working
+so far: web commit (post-commit hook and all), diff, add (under certain
+conditions), and remove. What's not working: with rcs_add(), iff any of the
+new page's parent dirs aren't already under CVS control and the post-commit
+hook is enabled, the browser and ikiwiki stall for several seconds trying
+to add it, then time out. (If I kill ikiwiki when this is happening, it cvs
+adds the topmost parent that needed adding; if I wait for timeout, it
+doesn't. I think.) If I disable the post-commit hook and do the same kind
+of thing, the page is created and saved.
+
+In case you're lucky enough not to know, cvs adds on directories are weird
+-- they operate immediately against the repository, unlike file adds:
+
+ $ cvs add randomdir
+ Directory /Users/schmonz/Documents/cvswiki/repository/ikiwiki/randomdir added to the repository
+
+I was able to work out that when I'm seeing this page save misbehavior, my
+plugin is somewhere inside `system("cvs", "-Q", "add", "$file")`, which was
+never returning. If I changed it to anything other than cvs it iterated
+correctly over all the parent dirs which needed to be added to CVS, in the
+proper order. (cvs add isn't recursive, sadly.)
+
+Can you offer an educated guess what's going wrong here? --[[Schmonz]]
+
+> Got `rcs_recentchanges` working, believe it or not, thanks to [cvsps](http://www.cobite.com/cvsps/). If I can figure out this interaction between the post-commit hook and `cvs add` on directories, the CVS plugin is mostly done. Could it be a locking issue? Where should I be looking? Any suggestions appreciated. --[[Schmonz]]
+
+>> Okay, it is definitely a locking issue. First, on the conjecture that
+>> `cvs add <directory>` was triggering the post-commit hook and confusing
+>> ikiwiki, I wrapped the ikiwiki post-commit binary with a shell script
+>> that exited 0 if the triggering file was a directory. The first half of
+>> the conjecture was correct -- my wrapper got triggered -- but the web
+>> add of `one/two/three.mdwn` (where `one` and `two` weren't existing
+>> CVS-controlled dirs) remained hung as before. There were two ikiwiki
+>> processes running. On a whim, I killed the one with the higher PID; `cvs
+>> add one` immediately completed successfully, then back to a hang and two
+>> ikiwiki processes. I killed the newer one again and then `cvs add
+>> one/two` and `cvs add one/two/three.mdwn` completed and the web add was
+>> successful. --[[Schmonz]]
+
+>>> Aaaaaand I was wrong about the second half of the conjecture being
+>>> wrong. The wrapper script wasn't correctly identifying directories;
+>>> with that fixed, everything works. I've created a
+>>> [[plugins/contrib/cvs]] plugin page. Thanks for listening. :-)
+>>> --[[Schmonz]]
+
+>> Here is a comment I committed to my laptop from Madrid Airport before
+>> your most recent updates, in case it's still useful:
+>>
+>> Locking certianly seems likely to be a problem. ikiwiki calls `rcs_add`
+>> *before* disabling the post-commit plugin, since all over VCS allow
+>> adding something in a staged manner. You can see this in, for example,
+>> `editpage.pm` lines 391+.
+>>
+>> So I guess what happens is that ikiwiki has taken the wiki lock, calls
+>> `rcs_add`, which does a `cvs add`, which runs the post commit hook,
+>> since it is not disabled -- which blocks waiting for the wiki lock.
+>>
+>> I guess you can fix this in either of three ways: Modify lots of places
+>> in ikiwiki to disable the post commit hook before calling `rcs_add`,
+>> or make cvs's `rcs_add` temporarily disable the commit hook and
+>> re-enable it (but only if it was not already disabled, somehow),
+>> or make cvs's `rcs_add` only make note that it needs to call `cvs add`
+>> later, and do so at `rcs_commit`. The last of these seems easist,
+>> especially since ikiwiki always commits after an add, in the same
+>> process, so you could just use a temporary list of things to add.
+>> --[[Joey]]
+
+>>> Thanks for the comments. Attempting to set up a wiki on a different system with a different version of `cvs`, I've encountered a new locking problem within CVS: `cvs commit` takes a write lock, post-commit ikiwiki calls `rcs_update()`, `cvs update` wants a read lock and blocks. The easiest fix I can think of is to make `cvs commit` return and relinquish its lock -- so instead of my wrapper script `exec`ing ikiwiki's post-commit hook, I amp it off and exit 0. Seems to do the trick and, if I grok ikiwiki's behavior here, is not dangerous. (Beats me why my development `cvs` doesn't behave the same WRT locking.)
+
+>>> I was all set to take your third suggestion, but now that there's more than one CVS oddity fixed trivially in a wrapper script, I think I prefer doing it that way.
+
+>>> I'd be glad for the CVS plugin to be included in ikiwiki, if and when you deem it ready. Please let me know what needs to be done for that to happen. --[[Schmonz]]
-[[meta title="Revision Control Systems"]]
+[[!meta title="Revision Control Systems"]]
Ikiwiki supports using several revision control systems for storing page
histories.
[[git]] is another well-tested option.
These are all the supported revision control systems:
-[[inline pages="rcs/* and !*/Discussion and !rcs/details" archive=yes]]
+[[!inline pages="rcs/* and !*/Discussion and !rcs/details" archive=yes]]
There is a page with [[details]] about how the different systems work with
ikiwiki, for the curious.
--- /dev/null
+[Darcs](http://darcs.new) is a distributed revison control
+system. Ikiwiki supports storing a wiki in a
+Darcs repository.
+
+An Ikiwiki wrapper is run by the `posthook` to update a wiki whenever commits
+or remote pushes come in. When running as a [[cgi]] with Darcs, ikiwiki
+automatically commits edited pages, and uses the Darcs history to generate the
+[[RecentChanges]] page.
+
+Example for a `_darcs/prefs/defaults` file in `$SRCDIR`:
+
+ apply posthook /path/to/repository/_darcs/ikiwiki-wrapper
+ apply run-posthook
+
+See also [[todo/darcs|todo/darcs]]
A few bits about the RCS backends
-[[toc ]]
+[[!toc ]]
## Terminology
W "belongs" to ikiwiki and should not be edited directly.
-## [darcs](http://darcs.net/) (not yet included)
+## [[darcs]]
-Support for using darcs as a backend is being worked on by [Thomas
-Schwinge](mailto:tschwinge@gnu.org), although development is on hold curretly.
-There is a patch in [[todo/darcs]].
+Regarding the repository layout: There are two darcs repositories. One is the `srcdir`, the other we'll call `master`.
-### How will it work internally?
+* HTML is generated from `srcdir`.
+* CGI edits happen in `srcdir`.
+* The backend pulls updates from `master` into `srcdir`, i.e. darcs commits should happen to `master`.
+* `master` calls ikiwiki (through a wrapper) in its apply posthook, i.e. `master/_darcs/prefs/defaults` should look like this:
-``Master'' repository R1.
-
-RCS commits from the outside are installed into R1.
-
-HTML is generated from R1. HTML is automatically generated (by using a
-``post-hook'') each time a new change is installed into R1. It follows
-that rcs_update() is not needed.
-
-There is a working copy of R1: R2.
-
-CGI operates on R2. rcs_commit() will push from R2 to R1.
-
-You browse the wiki on R1 and web-edit it on R2. This means for example
-that R2 needs to be updated from R1 if you are going to web-edit a page,
-as the user otherwise might be irritated otherwise...
-
-How do changes get from R1 to R2? Currently only internally in
-rcs\_commit(). Is rcs\_prepedit() suitable?
-
-It follows that the HTML rendering and the CGI handling can be completely
-separated parts in ikiwiki.
-
-What repository should [[RecentChanges]] and History work on? R1?
-
-#### Rationale for doing it differently than in the Subversion case
-
-darcs is a distributed RCS, which means that every checkout of a
-repository is equal to the repository it was checked-out from. There is
-no forced hierarchy.
-
-R1 is nevertheless called the master repository. It's used for
-collecting all the changes and publishing them: on the one hand via the
-rendered HTML and on the other via the standard darcs RCS interface.
-
-R2, the repository the CGI operates on, is just a checkout of R1 and
-doesn't really differ from the other checkouts that people will branch
-off from R1.
-
-(To be continued.)
-
-#### Another possible approach
-
-Here's what I (tuomov) think, would be a “cleaner” approach:
-
- 1. Upon starting to edit, Ikiwiki gets a copy of the page, and `darcs changes --context`.
- This context _and_ the present version of the page are stored in as the “version” of the
- page in a hidden control of the HTML.
- Thus the HTML includes all that is needed to generate a patch wrt. to the state of the
- repository at the time the edit was started. This is of course all that darcs needs.
- 2. Once the user is done with editing, _Ikiwiki generates a patch bundle_ for darcs.
- This should be easy with existing `Text::Diff` or somesuch modules, as the Web edits
- only concern single files. The reason why the old version of the page is stored in
- the HTML (possibly compressed) is that the diff can be generated.
- 3. Now this patch bundle is applied with `darcs apply`, or sent by email for moderation…
- there are many possibilities.
-
-This approach avoids some of the problems of concurrent edits that the previous one may have,
-although there may be conflicts, which may or may not propagate to the displayed web page.
-(Unfortunately there is not an option to `darcs apply` to generate some sort of ‘confliction resolution
-bundle’.) Also, only one repository is needed, as it is never directly modified
-by Ikiwiki.
-
-This approach might be applicable to other distributed VCSs as well, although they're not as oriented
-towards transmitting changes with standalone patch bundles (often by email) as darcs is.
-
-> The mercurial plugin seems to just use one repo and edit it directly - is
-> there some reason that's okay there but not for darcs? I agree with tuomov
-> that having just the one repo would be preferable; the point of a dvcs is
-> that there's no difference between one repo and another. I've got a
-> darcs.pm based on mercurial.pm, that's almost usable... --bma
-
->> IMHO it comes down to whatever works well for a given RCS. Seems like
->> the darcs approach _could_ be done with most any distributed system, but
->> it might be overkill for some (or all?) While there is the incomplete darcs
->> plugin in [[todo/darcs]], if you submit one that's complete, I will
->> probably accept it into ikiwiki.. --[[Joey]]
-
->>> I'd like to help make a robust darcs (2) backend. I also think ikiwiki should use
->>> exactly one darcs repo. I think we can simplify and say conflicting web
->>> edits are not allowed, like most current wiki engines. I don't see that
->>> saving (so much) context in the html is necessary, then.
->>> bma, I would like to see your code. --[[Simon_Michael]]
->>> PS ah, there it is. Let's continue on the [[todo/darcs]] page.
+ apply posthook ikiwrap
+ apply run-posthook
+* The backend pushes CGI edits from `srcdir` back into `master` (triggering the apply hook).
+* The working copies in `srcdir` and `master` should *not* be touched by the user, only by the CGI or darcs, respectively.
## [[Git]]
command to save disk space.
Note that, as a rule of thumb, you should always put the rcs wrapper (`post-update`)
-into the master repository (`.git/hooks/`) as can be noticed in the Git wrappers of
-the sample [[ikiwiki.setup]].
+into the master repository (`.git/hooks/`).
Here is how a web edit works with ikiwiki and git:
* git-commit in the remote repository
* git-push, pushes the commit to the master repo on the server
+* (Optionally, the master repo's pre-receive hook runs, and checks that the
+ update only modifies files that the pushing user is allowed to update.
+ If not, it aborts the receive.)
* the master repo's post-update hook notices this update, and runs ikiwiki
* ikiwiki notices the modifies page source, and compiles it
## [[tla]]
+Nobody really understands how tla works. ;-)
+
## rcs
There is a patch that needs a bit of work linked to from [[todo/rcs]].
-[[meta title="Git"]]
+[[!meta title="Git"]]
[Git][git] is a distributed revison control system originally developed for
the Linux kernel. Ikiwiki supports storing a wiki in git.
does not have a working tree checked out) at the root, and various
working clones (with working directories) as leaf nodes. The root
(bare) repository is meant to be pushed to and pulled from the various
-working clones. The image below displays the relationship between the
-root repository and the clone repositories (this is not a directory
-layout):
-
-
+working clones.
One of the leaf node clone repositories is special; it has working
-directory which is used to compile the wiki from, and is also used by the
+directory which is used to compile the wiki, and is also used by the
[[cgi]] to commit changes made via the web interface. It is special
-since the `post-commit` hook for the bare root repository is used to
+since the `post-update` hook for the bare root repository is used to
trigger an update of this repository, and then an ikiwiki refresh
updates the published wiki itself.
repositories will push to/pull from. It is a bare repository, since
there are problems pushing to a repository that has a working
directory. This is called _repository_ in [[ikiwiki-makerepo]]'s
- manual page. Nominally, this bare repository has a `post-commit` hook
+ manual page. Nominally, this bare repository has a `post-update` hook
that either is or calls ikiwiki's git wrapper, which changes to the
- working directory for ikiwiki, does a _git pull_, and refreshes ikiwiki
+ working directory for ikiwiki, does a `git pull`, and refreshes ikiwiki
to regenerate the wiki with any new content. The [[setup]] page describes
how to do this.
hack on your wiki. you can commit local changes to the version on
the laptop, perhaps while offline. Any new content should be pushed to the
bare master repository when you are ready to publish it, and then
- the post-commit hook of the bare repository will ensure that the
+ the post-update hook of the bare repository will ensure that the
ikiwiki's source directory is updated, and the ikiwiki refreshed
with the new content.
Instead, clone the bare repository as mentioned above, and push
**only** to the bare repository.
-The ikiwiki `post-commit` hook should be put in the bare repository.
+The ikiwiki `post-update` hook should be put in the bare repository.
## git repository with multiple committers
group. Take care that ikiwiki uses a umask that does not cause files in
the srcdir to become group writable. (umask 022 will work.)
+## git repository with untrusted committers
+
+By default, anyone who can commit to the git repository can modify any file
+on the wiki however they like. A `pre-receive` hook can be set up to limit
+incoming commits from untrusted users. Then the same limits that are placed
+on edits via the web will be in effect for commits to git for the users.
+They will not be allowed to edit locked pages, they will only be able to
+delete pages that the [[plugins/remove]] configuration allows them to
+remove, and they will only be allowed to add non-page attachments that the
+[[plugins/attachment]] configuration allows.
+
+To enable this, you need to set up the git repository to have multiple
+committers. Trusted committers, including the user that ikiwiki runs as,
+will not have their commits checked by the `pre-receive` hook. Untrusted
+committers will have their commits checked. The configuration settings to
+enable are `git_test_receive_wrapper`, which enables generation of a
+`pre-receive` hook, and `untrusted_committers`, which is a list of
+usernames of the untrusted committers.
+
+Note that when the `pre-receive` hook is checking incoming changes, it
+ignores the git authorship information, and uses the username of the unix
+user who made the commit. Then tests including the `locked_pages` [[PageSpec]]
+are checked to see if that user can edit the pages in the commit.
+
+You can even set up an [[anonymous_user|tips/untrusted_git_push]], to allow
+anyone to push changes in via git rather than using the web interface.
+
## Optionally using a local wiki to preview changes
When working on the "working clones" to add content to your wiki,
gitorigin_branch => "",
## git post-commit wrapper
- wrapper => "/working/dir/.git/hooks/post-commit",
+ git_wrapper => "/working/dir/.git/hooks/post-commit",
Then just committing should refresh the private ikiwiki on the local
host. Now just run `ikiwiki -setup localwiki.setup -getctime` and
versions of git will have a `post-merge` hook that should work for
this purpose.
+## Fix for error on git pull origin
+
+Error message when running git pull origin:
+
+ You asked me to pull without telling me which branch you
+ want to merge with, and 'branch.master.merge' in
+ your configuration file does not tell me either. Please
+ name which branch you want to merge on the command line and
+ try again (e.g. 'git pull <repository> <refspec>').
+ See git-pull(1) for details on the refspec.
+
+ If you often merge with the same branch, you may want to
+ configure the following variables in your configuration
+ file:
+
+ branch.master.remote = <nickname>
+ branch.master.merge = <remote-ref>
+ remote.<nickname>.url = <url>
+ remote.<nickname>.fetch = <refspec>
+
+ See git-config(1) for details.
+
+The solution is to run this command in your srcdir:
+
+ git config branch.master.remote origin
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
+
+> Ikiwiki is designed so that you don't have to worry about this kind of permissions issue.
+> Instead you can just configure the ikiwiki.cgi, in the setup file, to be suid to your
+> user. Then there's no need to let the web server's user modify files at all. --[[Joey]]
+
+
+## using a local wiki to preview changes: an srcdir needed?
+I have read the hints about using a local wiki to preview changes, but I haven't understood: is it assumed that I should also have a separate "srcdir" for this local preview-wiki (as it is done for the main wiki site), or I could point the local ikiwiki's "srcdir" to the working dir? Can something bad happen if I do this? I guess no, because--as I see it--the reason to have 2 repos for the main site was only enabling pushing to it, so it's a peculiarity of git, and not a requirement for a clean functioning of ikiwiki.
+
+Ok, probably, I have answered my question myself, but I'll let this comment stay here, if someone else will be tinking about the same issue. --Ivan Z.
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 = ikiwiki --setup /path/to/ikiwiki.setup --post-commit
+ incoming = ikiwiki --setup /path/to/ikiwiki.setup --post-commit
+
+Do not use `commit` or `precommit` hooks or ikiwiki will run into a dead lock when committing in `$SRCDIR`. Also note that `--post-commit` and not `--refresh` must be used to avoid dead locking when editing the pages via CGI interface.
+
+See also [[todo/mercurial|todo/mercurial]]
way Monotone handles conflicts. At present, if there is a conflict, then
Ikiwiki will commit a revision with conflict markers before presenting it
to the user. This is ugly, but there is no clean way to fix it at present.
+
+Also note that not all recent ikiwiki features have been implemented in the
+monotone plugin. At the moment we're missing:
+
+ * [[todo/Untrusted_push_in_Monotone]]
commits edited pages to the Arch repostory, and uses the Arch
log to generate the [[RecentChanges]] page.
-Note that the tla support needs the [[cpan MailTools]] perl module.
+Note that the tla support needs the [[!cpan MailTools]] perl module.
+[[!if test="enabled(meta)" then="""
[[!meta title="RecentChanges"]]
+"""]]
Recent changes to this wiki:
[[!inline pages="internal(recentchanges/change_*) and !*/Discussion"
Released 29 April 2006.
-The 1.x series changed a great deal over the more than 50 releases in its
-lifetime. It is now in maintenance mode, only security issues or really bad
-bugs will be fixed in 1.x going forward.
+The 1.x series is no longer supported.
----
Released 30 April 2007.
-The 2.x series is expected to undergo continuing development for some time,
-adding improvements and new features, but avoiding changes that break
-backwards compatability.
+The 2.x series is now in maintenance mode. Only security fixes and fixes for
+really bad bugs will be applied going forward.
----
# 3.0
-Still in the early planning stages, version 3.0 will be an opportunity to
-make significant transitions.
-
-* Default to using prefix_directives.
+Version 3.0 is an opportunity to make significant transitions.
+Read [[tips/upgrade_to_3.0]] for the steps you will need to
+follow when upgrading your wiki to this version.
+
+The highlights of the changes in version 3.0 include:
+
+* Support for uploading [[attachments|plugins/attachment]].
+* Can [[plugins/rename]] and [[plugins/remove]] pages and files via the web.
+* [[Web_based_setup|plugins/websetup]].
+* Blog-style [[plugins/comments]] as an alternative to Discussion pages.
+* Many other new plugins including [[plugins/htmlbalance]], [[plugins/format]],
+ [[plugins/progress]], [[plugins/color]], [[plugins/autoindex]],
+ [[plugins/cutpaste]], [[plugins/hnb]], [[plugins/creole]], [[plugins/txt]],
+ [[plugins/amazon_s3]], [[plugins/pinger]], [[plugins/pingee]],
+ [[plugins/edittemplate]]
+* The RecentChanges page is compiled statically, not generated from the CGI.
+* Support for additional revision control systems: [[rcs/bzr]],
+ [[rcs/monotone]]
+* Support for [[tips/untrusted_git_push]].
+* A new version (3.00) of the plugin API, exporting additional
+ commonly used functions from `IkiWiki.pm`.
+* Nearly everything in ikiwiki is now a plugin, from WikiLinks to page
+ editing, to RecentChanges.
+* Far too many bug fixes, features, and enhancements to list here.
+
+Released 31 December, 2008.
+
+The 3.x series is expected to undergo continuing development for some time,
+adding improvements and new features, but avoiding changes that break
+backwards compatability.
----
# future goals
-* Improved [[todo/html]] stylesheets and templates.
- _(status: [[css_market]] exists; it could always provide more stylesheets. No alternate templates yet, though.)_
-* More documentation in the basewiki, including documentation for all enabled plugins. Probably need some solution for [[todo/conditional_underlay_files]], too.
* Conversion support for existing other wikis.
(Being worked on for MoinMoin and TWiki by [[Josh_Triplett|JoshTriplett]]
and Jamey Sharp; support for other wikis should fit into the same
framework.)
-* [[TODO]], [[bugs]], [[soc]], ...
+* [[TODO]], [[bugs]], ...
--- /dev/null
+User-Agent: *
+Disallow: /ikiwiki.cgi
-This is the SandBox, a page anyone can edit to try out ikiwiki.
+This is the [[SandBox]], a page anyone can edit to try out ikiwiki (version [[!version ]]).
-blather
+----
+2009/7/13 Monday Blue...\\
+While working on [[http://eoffice.im.fju.edu.tw/phpbb/viewtopic.php?p=27199|[97] Phpbb 與 Dokuwiki 之間的往來]] (External Link to //http://eoffice.im.fju.edu.tw/phpbb/viewtopic.php?p=27199// not working?), surf Internet for Wikis supporting //Creole V1.0//, found this site.
+
+* I thought that creole markup is used by ikiwiki...
+* Thought about using //SVN/CVS// server, however with different idea
+* Kinda curious why **Tcl** does not show her face in this Wiki arena
+* It looks like that I was wrong, from Wikipedia Creole page it mention that ikiwiki is also adopting Creole markup.
+
+---
+
+Guten Morgen aus Deutschland. Wir mögen Umläuter (ich weiß, der Plural ist falsch, aber dafür hat er einen). Die sind heutzutage kein Ärgernis mehr.
+
+&#x263a; becomes ☺
+
+<script>alert("If this pops, ikiwiki is not cross site scripting safe."); /* Fortunately, this does not work. */</script>
+---
+I try to have a discussion page !!!
----
+Testing OpenID some more..
+
+test more test
+[[中文显示]]
+
Here's a paragraph.
+The following code block is pre-formatted:
+
+ Testing what
+ pre-formatted code blocks
+ look like.
+
Here's another one with *emphasised* text.
# Header
* four
* five
-* a new list
- * with sub heads
- * like this
-
----
-[[template id=note text="this is generated by the [[plugins/haiku]] plugin"]]
-[[haiku hint="sandbox play"]]
+[[!template id=note text="this is generated by the [[plugins/haiku]] plugin"]]
+[[!haiku hint="sandbox play"]]
----
* [](http://ikiwiki.info)
* <a href="http://www.google.com/">plain old html link</a>
* [[foo]]
-* WikiLink
-----
-This sandbox is also a [[ikiwiki/blog]]!
+This SandBox is also a [[blog]]!
+
+[[!inline pages="sandbox/* and !*/Discussion" rootpage="sandbox" show="4" archive="yes"]]
+
+--------
+
+This gives an example of inline code: `tar | netcat` is a nice way to transfer bulk files over the net
+
+But, of course, rsync is better.
+
+----
+
+Let's see what happens... ~~
+
+#中文标题一
+##中文标题二
+###中文标题三
+...
+######中文标题六
+
+###正文:
+
+君不见,黄河之水天上来,奔流到海不复回。
+
+君不见,高堂明镜悲白发,朝如青丝暮成雪。
+
+人生得意须尽欢,莫使金樽空对月。
+
+天生我材必有用,千金散尽还复来。
+
+###列表:
+
+* 天空
+
+ 1. 蓝色的
+ 2. 好高啊
+
+* 海洋
+
+ 1. 有鱼
+
+ * 鲸鱼
+ * 鲨鱼
+
+
+* 大地
+
+###链接:
+
+[谷歌](http://www.google.com)
+
+###引用:
+
+> 一级引用
+>
+> 一级引用
+>
+> > 二级引用
+>
+>> 没有空格也可以
+>>> 三级引用
+>
+> 回到一级引用
+
+
+----
+
+
+testing
+
+--
+[[!toc levels=2]]
-[[inline pages="sandbox/* and !*/Discussion" rootpage="sandbox" show="4" archive="yes"]]
+[[Mamma Mia]]
--- /dev/null
+This is a testing Blag-Entry.
+/me loves blagging.
+
+ * Entry one
+ * entry two
+
--- /dev/null
+Just a test page ...
+
+... to see what happens.
--- /dev/null
+!!!Heading Three
+
+Itemized
+* list
+* of
+* things
+
+or not
+1. mom
+1. hi
+1. there
+
+
+
+!!!Heading Three
+
+Itemized
+* list
+* of
+* things
+
+or not
+1. mom
+1. hi
+1. there
--- /dev/null
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow>
+ <msup>
+ <mfenced open="(" close=")">
+ <mrow>
+ <mi>a</mi>
+ <mo>+</mo>
+
+ <mi>b</mi>
+ </mrow>
+ </mfenced>
+ <mn>2</mn>
+ </msup>
+ <mo>-</mo>
+ <msub>
+
+ <mfenced open="{" close="}">
+ <mrow>
+ <mi>x</mi>
+ <mo>+</mo>
+ <mi>y</mi>
+ </mrow>
+ </mfenced>
+
+ <mi>i</mi>
+ </msub>
+ </mrow>
+</math>
+<br>
+test <b>test</b><abbr title="test">T.</abbr> <h1>test</h1>
+<a href="https://bugzilla.mozilla.org">øđ</a>
--- /dev/null
+what happens?
--- /dev/null
+[[!teximg code="E = - \frac{Z^2 \cdot \mu \cdot e^4}{32\pi^2 \epsilon_0^2 \hbar^2 n^2}" ]]
+
--- /dev/null
+# Title with $\TeX$
+
+* How about some math?
+* $\frac{1}{2} = \frac{3}{6}$
+
+and teximg? [[!teximg code="\frac{1}{2}"]]
-I recall testing this too, but I'm not sure where the test went. Let's try again. -- [[JonDowland]]
+I recall testing this too, but I'm not sure where the test went. Let's try again. -- [[users/Jon]]
Context: [[todo/discussion_page_as_blog/discussion/castle]]
--- /dev/null
+normally a sandbow doesn't have a discussion page
+but it's a sandbox
+
+-
+little light
+ikiwiki looks great
--- /dev/null
+Foobaka bakfoo.
--- /dev/null
+testing my openid provider @ www.steve.org.uk
Testing nested inlines:
-[[inline pages="sandbox/test_nested_inlines/* and !sandbox/test_nested_inlines/*/*" feeds="no"]]
+[[!inline pages="sandbox/test_nested_inlines/* and !sandbox/test_nested_inlines/*/*" feeds="no"]]
--- /dev/null
+~를 어떻게 할까~
--- /dev/null
+
+Wow test
others edit pages in your wiki, then some possible security issues do need
to be kept in mind.
-[[toc levels=2]]
+[[!toc levels=2]]
----
## setup files
Setup files are not safe to keep in the same revision control repository
-with the rest of the wiki. Just don't do it. [[ikiwiki.setup]] is *not*
-used as the setup file for this wiki, BTW.
+with the rest of the wiki. Just don't do it.
## page locking can be bypassed via direct commits
The htmlscrubber did not block javascript in uris. This was fixed by adding
a whitelist of valid uri types, which does not include javascript.
-([[cve CVE-2008-0809]]) Some urls specifyable by the meta plugin could also
+([[!cve CVE-2008-0809]]) Some urls specifyable by the meta plugin could also
theoretically have been used to inject javascript; this was also blocked
-([[cve CVE-2008-0808]]).
+([[!cve CVE-2008-0808]]).
This hole was discovered on 10 February 2008 and fixed the same day
with the release of ikiwiki 2.31.1. (And a few subsequent versions..)
Cross Site Request Forging could be used to constuct a link that would
change a logged-in user's password or other preferences if they clicked on
the link. It could also be used to construct a link that would cause a wiki
-page to be modified by a logged-in user. ([[cve CVE-2008-0165]])
+page to be modified by a logged-in user. ([[!cve CVE-2008-0165]])
These holes were discovered on 10 April 2008 and fixed the same day with
the release of ikiwiki 2.42. A fix was also backported to Debian etch, as
hashes (using Eksblowfish).
If you use the [[plugins/passwordauth]] plugin, I recommend upgrading to
-ikiwiki 2.48, installing the [[cpan Authen::Passphrase]] perl module, and running
+ikiwiki 2.48, installing the [[!cpan Authen::Passphrase]] perl module, and running
`ikiwiki-transition hashpassword` to replace all existing cleartext passwords
with strong blowfish hashes.
This hole allowed ikiwiki to accept logins using empty passwords, to openid
accounts that didn't use a password. It was introduced in version 1.34, and
fixed in version 2.48. The [bug](http://bugs.debian.org/483770) was
-discovered on 30 May 2008 and fixed the same day. ([[cve CVE-2008-0169]])
+discovered on 30 May 2008 and fixed the same day. ([[!cve CVE-2008-0169]])
I recommend upgrading to 2.48 immediatly if your wiki allows both password
and openid logins.
+
+## Malformed UTF-8 DOS
+
+Feeding ikiwiki page sources containing certian forms of malformed UTF-8
+can cause it to crash. This can potentially be used for a denial of service
+attack.
+
+intrigeri discovered this problem on 12 Nov 2008 and a patch put in place
+later that day, in version 2.70. The fix was backported to testing as version
+2.53.3, and to stable as version 1.33.7.
This tutorial will walk you through setting up a wiki with ikiwiki.
-[[toc ]]
+[[!toc ]]
-## [[Download]] and [[install]] ikiwiki.
+## Install ikiwiki
If you're using Debian or Ubuntu, ikiwiki is an `apt-get install ikiwiki` away.
If you're not, see the [[download]] and [[install]] pages.
-## Decide where your wiki's files will go.
+## Create your wiki
-As a wiki compiler, ikiwiki builds a wiki from files in a source directory,
-and outputs the files to a destination directory. If you keep your wiki in
-a version control system, the source directory will contain a working copy
-checked out from the version control system.
+All it takes to create a fully functional wiki using ikiwiki is running
+one command.
+[[!template id=note text="""
+For more control, advanced users may prefer to set up a wiki
+[[by_hand|byhand]].
+"""]]
-For the purposes of this tutorial, we'll set shell variables
-for these locations, and use those variables in the commands that follow.
+ % ikiwiki -setup /etc/ikiwiki/auto.setup
- SRCDIR=~/wikiwc
- DESTDIR=~/public_html/wiki/
+Or, set up a blog with ikiwiki, run this command instead.
-Note that ikiwiki owns the working copy directory; do not perform your own
-edits in ikiwiki's working copy.
+ % ikiwiki -setup /etc/ikiwiki/auto-blog.setup
-## Create the beginnings of your wiki.
+Either way, it will ask you a couple of questions.
-This will create a simple main page for the wiki.
+ What will the wiki be named? foo
+ What revision control system to use? git
+ What wiki user (or openid) will be admin? joey
+ Choose a password:
- mkdir $SRCDIR
- cd $SRCDIR
- $EDITOR index.mdwn
+Then, wait for it to tell you an url for your new site..
-In the editor, you could start by entering a simple page like
-[[toggle id=page text="this one"]].
-[[toggleable id=page text="""
- Welcome to your new wiki.
+ Successfully set up foo:
+ url: http://example.com/~joey/foo
+ srcdir: ~/foo
+ destdir: ~/public_html/foo
+ repository: ~/foo.git
+ To modify settings, edit ~/foo.setup and then run:
+ ikiwiki -setup ~/foo.setup
- All wikis are supposed to have a \[[SandBox]],
- so this one does too.
+Done!
- ----
+## Using the web interface
- This wiki is powered by [ikiwiki](http://ikiwiki.info).
-"""]]
-
-See [[ikiwiki/formatting]] for details about the markup language.
+Now you can go to the url it told you, and edit pages in your new wiki
+using the web interface.
-Note that several [[standard_wiki_pages|basewiki]] will be added to your
-wiki, from files in `/usr/share/ikiwiki/basewiki/`, so your wiki will
-automatically get a [[SandBox]], and some other useful pages.
+(If the web interface doesn't seem to allow editing or login, you may
+need to configure [[configure_the_web_server|tips/dot_cgi]].)
-## Build your wiki for the first time.
+## Checkout and edit wiki source
- ikiwiki --verbose $SRCDIR $DESTDIR --url=http://example.org/~you/wiki/
+Part of the fun of using ikiwiki is not being limited to using the
+web for editing pages, and instead using your favorite text editor and
+[[Revision_Control_System|rcs]].
-Replace the url with the real url to your wiki. You should now
-be able to visit the url and see your wiki.
+To do this, you need to check out a copy of the source to your wiki.
+(You should avoid making changes directly to the `srcdir`, as that
+checkout is reserved for use by ikiwiki itself.)
-## Add content to your wiki.
+Depending on which [[Revision_Control_System|rcs]] you chose to use,
+you can run one of these commands to check out your own copy of your wiki's
+source. (Remember to replace "foo" with the real directory name.)
-Continue editing or adding pages and rebuilding the wiki.
-
-To quickly get started on a common task like blogging with ikiwiki, you
-can copy in files from the [[examples]]. The examples are located in
-`doc/examples/` in the ikiwiki source package.
+ git clone foo.git foo.src
+ svn checkout file://`pwd`/foo.svn/trunk foo.src
+ bzr clone foo foo.src
+ hg clone foo foo.src
+ # TODO monotone, tla
-You can experiment with other ikiwiki parameters such as `--wikiname`
-and `--rebuild` too. Get comfortable with its command line (see
-[[usage]]).
+Now to edit pages by hand, go into the directory you checked out (ie,
+"foo.src"), and fire up your text editor to edit `index.mdwn` or whatever
+other page you want to edit. If you chose to set up a blog, there is even a
+sample first post in `posts/first_post.mdwn` that you can edit.
-## Add a setup file.
+Once you've edited a page, use your revision control system to commit
+the changes. For distributed revision control systems, don't forget to push
+your commit.
-By now you should be getting tired of typing in all the command line
-options each time you change something in your wiki's setup. Time to
-introduce setup files.
-
-A sample setup file is [[ikiwiki.setup]]. Download it (or copy it from
-`doc/ikiwiki.setup` in the ikiwiki sources), and edit it. Note that this
-file should *not* be put in your wiki's directory with the rest of the
-files. A good place to put it is in a ~/.ikiwiki/ subdirectory.
-
-Most of the options, like `wikiname` in the setup file are the same as
-ikiwiki's command line options (documented in [[usage]]. `srcdir` and
-`destdir` are the two directories you specify when running ikiwiki by
-hand. Make sure that these are pointing to the right directories, and
-read through and configure the rest of the file to your liking.
-
-When you're satisfied, run `ikiwiki --setup ikiwiki.setup`, and it
-will set everything up.
+Once the commit reaches the repository, ikiwiki will notice it, and
+automatically update the wiki with your changes.
-## Turn on additional features.
+## Customizing the wiki
-Now you have a basic wiki with a configuration file. Time to experiment
-with ikiwiki's many features.
-
-Let's first enable a key wiki feature and set up [[CGI]] to allow
-editing the wiki from the web. Just edit ikiwiki.setup, uncomment the
-block for the cgi wrapper, make sure the filename for the cgi wrapper
-is ok, run `ikiwiki --setup ikiwiki.setup`, and you're done!
+There are lots of things you can configure to customize your wiki.
+These range from changing the wiki's name, to enabling [[plugins]],
+to banning users and locking pages.
-There are lots of other configuration options in ikiwiki.setup that you
-can uncomment, configure, and enable by re-running
-`ikiwiki --setup ikiwiki.setup`. Be sure to browse through all the
-[[plugins]]..
+If you log in as the admin user you configured earlier, and go to
+your Preferences page, you can click on "Wiki Setup" to customize many
+wiki settings and plugins.
-## Put your wiki in revision control.
+Some settings cannot be configured on the web, for security reasons or
+because misconfiguring them could break the wiki. To change these settings,
+you can manually edit the setup file, which is named something like
+"foo.setup". The file lists all available configuration settings
+and gives a brief description of each.
-At this point you might want to check your wiki in to a revision control
-system so you can keep track of changes and revert edits. Depending
-on the revision control system you choose, the way this is done varies.
+After making changes to this file, you need to tell ikiwiki to use it:
-Note that the .ikiwiki subdirectory is where ikiwiki keeps its state, and
-should be preserved, but not checked into revision control.
+ % ikiwiki -setup foo.setup
-The new [[ikiwiki-makerepo]] command automates setting up a wiki in
-revision control.
-
-[[toggle id=subversion text="Subversion"]]
-[[toggleable id=subversion text="""
- REPOSITORY=~/wikirepo
- ikiwiki-makerepo svn $SRCDIR $REPOSITORY
-"""]]
+## Customizing file locations
-[[toggle id=git text="Git"]]
-[[toggleable id=git text="""
- REPOSITORY=~/wiki.git
- ikiwiki-makerepo git $SRCDIR $REPOSITORY
-
-Please see [[rcs/git]] for detailed documentation about how
-ikiwiki uses git repositories, and some important caveats
-about using the git repositories.
-"""]]
-
-[[toggle id=mercurial text="Mercurial"]]
-[[toggleable id=mercurial text="""
- REPOSITORY=$SRCDIR
- ikiwiki-makerepo mercurial $SRCDIR
-"""]]
+As a wiki compiler, ikiwiki builds a wiki from files in a source directory,
+and outputs the files to a destination directory. The source directory is
+a working copy checked out from the version control system repository.
-[[toggle id=bazaar text="Bazaar"]]
-[[toggleable id=bazaar text="""
- REPOSITORY=$SRCDIR
- ikiwiki-makerepo bzr $SRCDIR
-"""]]
+When you used `auto.setup`, ikiwiki put the source directory, destination
+directory, and repository in your home directory, and told you the location
+of each. Those locations were chosen to work without customization, but you
+might want to move them to different directories.
-[[toggle id=tla text="TLA"]]
-[[toggleable id=tla text="""
- REPOSITORY=~/wikirepo
- tla make-archive me@localhost--wiki $REPOSITORY
- tla my-id "<me@localhost>"
- cd $SRCDIR
- tla archive-setup me@localhost--wiki/wiki--0
- tla init-tree me@localhost--wiki/wiki--0
- # Edit {arch}/=tagging-method and change the precious
- # line to add the .ikiwiki directory to the regexp.
- tla add *
- tla import
-"""]]
+First, move the destination directory and repository around.
+
+ % mv public_html/foo /srv/web/foo.com
+ % mv foo.git /srv/git/foo.git
-[[toggle id=monotone text="Monotone"]]
-[[toggleable id=monotone text="""
- # These instructions are standard instructions to import a directory into monotone
- # and set it up so that you don't need any passwords to use it
- REPOSITORY=~/.ikiwiki/mtn.db
- BRANCH=com.company.wikiname
- # remember the password you use in the next step and
- # substitute it for 'wikiKeyPass' in the get_passphrase() hook below
- # note the you should never generate two monotone keys with the same name
- mtn genkey web@machine.company.com
- mtn db init --db=$REPOSITORY
- mv $SRCDIR $SRCDIR-old
- cd $SRCDIR-old
- echo ".ikiwiki" > $SRCDIR-old/.mtn-ignore
- mtn --db=$REPOSITORY --branch=$BRANCH import . -m "initial import"
- cd ..
- mtn --db=$REPOSITORY --branch=$BRANCH checkout $SRCDIR
- mv $SRCDIR-old/.ikiwiki $SRCDIR
- cat << EOF > $SRCDIR/_MTN/monotonerc
- function get_passphrase (branchname)
- return "wikiKeyPass"
- end
- EOF
- rm -r $SRCDIR-old
-"""]]
+If you moved the repository to a new location, checkouts pointing at the
+old location won't work, and the easiest way to deal with this is to delete
+them and re-checkout from the new repository location.
+
+ % rm -rf foo
+ % git clone /src/git/foo.git
-## Configure ikiwiki to use revision control.
-
-Once your wiki is checked in to the revision control system,
-you should configure ikiwiki to use revision control. Edit your
-ikiwiki.setup, and uncomment the lines for the revision control system
-you chose to use. Be sure to set `svnrepo` to $REPOSITORY, if using
-subversion. Uncomment the block for the wrapper for your revision
-control system, and configure the wrapper path in that block
-appropriately (for Git, it should be `$REPOSITORY/hooks/post-update`).
-
-Once it's all set up, run `ikiwiki --setup ikiwiki.setup` once more.
-Now you should be able to edit files in $SRCDIR, and use your revision
-control system to commit them, and the wiki will automatically update.
-And in the web interface, RecentChanges should work, and files changed
-by web users will also be committed using revision control.
+Finally, edit the setup file. Modify the settings for `srcdir`, `destdir`,
+`url`, `cgiurl`, `cgi_wrapper`, `git_wrapper`, etc to reflect where
+you moved things. Remember to run `ikiwiki -setup` after editing the
+setup file.
## Enjoy your new wiki!
--- /dev/null
+This tutorial will walk you through setting up a wiki with ikiwiki,
+doing everything by hand. [[Setup]] has an easier method, but with less
+control.
+
+[[!toc ]]
+
+## Decide where your wiki's files will go.
+
+As a wiki compiler, ikiwiki builds a wiki from files in a source directory,
+and outputs the files to a destination directory. If you keep your wiki in
+a version control system, the source directory will contain a working copy
+checked out from the version control system.
+
+For the purposes of this tutorial, we'll set shell variables
+for these locations, and use those variables in the commands that follow.
+
+ SRCDIR=~/wikiwc
+ DESTDIR=~/public_html/wiki/
+
+Note that ikiwiki owns the working copy directory; do not perform your own
+edits in ikiwiki's working copy.
+
+## Create the beginnings of your wiki.
+
+This will create a simple main page for the wiki.
+
+ mkdir $SRCDIR
+ cd $SRCDIR
+ $EDITOR index.mdwn
+
+In the editor, you could start by entering a simple page like
+[[!toggle id=page text="this one"]].
+[[!toggleable id=page text="""
+ Welcome to your new wiki.
+
+ All wikis are supposed to have a \[[SandBox]],
+ so this one does too.
+
+ ----
+
+ This wiki is powered by [ikiwiki](http://ikiwiki.info).
+"""]]
+
+See [[ikiwiki/formatting]] for details about the markup language.
+
+Note that several [[standard_wiki_pages|basewiki]] will be added to your
+wiki, from files in `/usr/share/ikiwiki/basewiki/`, so your wiki will
+automatically get a [[SandBox]], and some other useful pages.
+
+## Build your wiki for the first time.
+
+ ikiwiki --verbose $SRCDIR $DESTDIR --url=http://example.org/~you/wiki/
+
+Replace the url with the real url to your wiki. You should now
+be able to visit the url and see your wiki.
+
+## Add content to your wiki.
+
+Continue editing or adding pages and rebuilding the wiki.
+
+To quickly get started on a common task like blogging with ikiwiki, you
+can copy in files from the [[examples]]. The examples are located in
+`doc/examples/` in the ikiwiki source package.
+
+You can experiment with other ikiwiki parameters such as `--wikiname`
+and `--rebuild` too. Get comfortable with its command line (see
+[[usage]]).
+
+## Add a setup file.
+
+By now you should be getting tired of typing in all the command line
+options each time you change something in your wiki's setup. Time to
+introduce setup files.
+
+To generate a setup file, use `ikiwiki --dumpsetup`. You can pass
+all the options have you been including at the command line, and they
+will be stored in the setup file.
+
+ ikiwiki $SRCDIR $DESTDIR --url=http://example.org/~you/wiki/ --dumpsetup ikiwiki.setup
+
+Note that this file should *not* be put in your wiki's directory with
+the rest of the files. A good place to put it is in a ~/.ikiwiki/
+subdirectory.
+
+Most of the options, like `wikiname` in the setup file are the same as
+ikiwiki's command line options (documented in [[usage]]). `srcdir` and
+`destdir` are the two directories you specify when running ikiwiki by
+hand. Make sure that these are pointing to the right directories, and
+read through and configure the rest of the file to your liking.
+
+When you're satisfied, run `ikiwiki --setup ikiwiki.setup`, and it
+will set everything up.
+
+## Turn on additional features.
+
+Now you have a basic wiki with a setup file. Time to experiment
+with ikiwiki's many features.
+
+Let's first enable a key wiki feature and set up [[CGI]] to allow
+editing the wiki from the web. Just edit ikiwiki.setup, uncomment the
+settings for the `cgi_wrapper`, make sure the filename for the cgi wrapper
+is ok, run `ikiwiki --setup ikiwiki.setup`, and you're done!
+
+There are lots of other configuration options in ikiwiki.setup that you
+can uncomment, configure, and enable by re-running
+`ikiwiki --setup ikiwiki.setup`. Be sure to browse through all the
+[[plugins]]..
+
+## Put your wiki in revision control.
+
+At this point you might want to check your wiki in to a revision control
+system so you can keep track of changes and revert edits. Depending
+on the revision control system you choose, the way this is done varies.
+
+Note that the .ikiwiki subdirectory is where ikiwiki keeps its state, and
+should be preserved, but not checked into revision control.
+
+The [[ikiwiki-makerepo]] command automates setting up a wiki in
+revision control.
+
+[[!toggle id=subversion text="Subversion"]]
+[[!toggleable id=subversion text="""
+ REPOSITORY=~/wikirepo
+ ikiwiki-makerepo svn $SRCDIR $REPOSITORY
+"""]]
+
+[[!toggle id=git text="Git"]]
+[[!toggleable id=git text="""
+ REPOSITORY=~/wiki.git
+ ikiwiki-makerepo git $SRCDIR $REPOSITORY
+
+Please see [[rcs/git]] for detailed documentation about how
+ikiwiki uses git repositories, and some important caveats
+about using the git repositories.
+"""]]
+
+[[!toggle id=mercurial text="Mercurial"]]
+[[!toggleable id=mercurial text="""
+ REPOSITORY=$SRCDIR
+ ikiwiki-makerepo mercurial $SRCDIR
+"""]]
+
+[[!toggle id=bazaar text="Bazaar"]]
+[[!toggleable id=bazaar text="""
+ REPOSITORY=$SRCDIR
+ ikiwiki-makerepo bzr $SRCDIR
+"""]]
+
+[[!toggle id=tla text="TLA"]]
+[[!toggleable id=tla text="""
+ REPOSITORY=~/wikirepo
+ tla make-archive me@localhost--wiki $REPOSITORY
+ tla my-id "<me@localhost>"
+ cd $SRCDIR
+ tla archive-setup me@localhost--wiki/wiki--0
+ tla init-tree me@localhost--wiki/wiki--0
+ # Edit {arch}/=tagging-method and change the precious
+ # line to add the .ikiwiki directory to the regexp.
+ tla add *
+ tla import
+"""]]
+
+[[!toggle id=monotone text="Monotone"]]
+[[!toggleable id=monotone text="""
+ # This assumes that you have already used "mtn genkey you@hostname".
+ REPOSITORY=~/wiki.monotone
+ ikiwiki-makerepo monotone $SRCDIR $REPOSITORY
+"""]]
+
+## Configure ikiwiki to use revision control.
+
+Once your wiki is checked in to the revision control system, you should
+configure ikiwiki to use revision control. Edit your ikiwiki.setup, set
+`rcs` to the the revision control system you chose to use. Be careful,
+you may need to use the 'fullname'. For example, 'hg' doesn't work, you
+should use mercurial. Be sure to set `svnrepo` to the directory for your
+repository, if using subversion. Uncomment the configuration for the wrapper
+for your revision control system, and configure the wrapper path appropriately
+(for Git, it should be the path to `hooks/post-update` inside the bare git repository).
+
+Once it's all set up, run `ikiwiki --setup ikiwiki.setup` once more.
+Now you should be able to edit files in $SRCDIR, and use your revision
+control system to commit them, and the wiki will automatically update.
+And in the web interface, RecentChanges should work, and files changed
+by web users will also be committed using revision control.
+
+## Enjoy your new wiki!
+
+Add yourself to [[IkiWikiUsers]]. And check out
+the [[tips]] to find out how to get more out of ikiwiki.
----
-I apologize if this is the incorrect forum for this question, but I am trying to get ikiwiki set up and running with git. I followed all the directions and all seems to work until I go back and try to make changes. The steps I am performing:
+I apologize if this is the incorrect forum for this question, but I am
+trying to get ikiwiki set up and running with git. I followed all the
+directions and all seems to work until I go back and try to make changes.
+The steps I am performing:
cd $SRCDIR (e.g. ~/ikisrc)
vim index.mdwn (add a couple lines)
git commit -a -m 'test'
git push
-I then get a long error message which reads in part "You asked me to pull without telling me which branch you
-want to merge with, and 'branch.master.merge' in your configuration file does not tell me either." From that point on, I get:
+I then get a long error message which reads in part "You asked me to pull
+without telling me which branch you want to merge with, and
+'branch.master.merge' in your configuration file does not tell me either."
+From that point on, I get:
sws@odin:~/dev/ikisrc$ git push
To /home/git/repos/myikiwiki.git
! [rejected] master -> master (non-fast forward)
error: failed to push to '/home/git/repos/myikiwiki.git'
-If I do a git clone ssh://odin/path/to/$REPOSITORY from another machine and try to edit I get the same error sequence. What am I doing wrong?
+If I do a git clone ssh://odin/path/to/$REPOSITORY from another machine and
+try to edit I get the same error sequence. What am I doing wrong?
+
+> I don't know. The only time I have seen this message is when
+> the master git repository was not bare. All current instructions and
+> `ikiwiki-makerepo` have a proper bare repo used for the master
+> repository, but perhaps you followed some old, broken instructions, or
+> forgot to make it bare? --[[Joey]]
-----
-I follow every steps of the setup procedure, change some templates and tried to modify some page through the web but was not able to do so. Every page seems to be locked by the adminuser user. When I remove the adminuser in the setup file, every ran fine. Did I miss something ? What is exactly the adminuser supposed to be allowed to ? Is he the only user allowed to modify pages ?
+I follow every steps of the setup procedure, change some templates and
+tried to modify some page through the web but was not able to do so. Every
+page seems to be locked by the adminuser user. When I remove the adminuser
+in the setup file, every ran fine. Did I miss something ? What is exactly
+the adminuser supposed to be allowed to ? Is he the only user allowed to
+modify pages ?
> This was a bug in ikwiki that was fixed in version 2.44. --[[Joey]]
+
+-----
+
+pI hope you guys can put up with an absolute newbie. I am fairly new to linux and completely new to Perl. I have just installed MoinMoin locally in my PC, running ubuntu 8.4 and was about to use it until I ran into your ikiwiki. I thought ikiwiki is a better fit for what I want to do, so am seriously considering installing it as well in ubuntu. Except that the install seems way beyond my understanding.
+
+Do i need to install git first? Which git -- the git-core? Ubuntu's instructions on installing the git-core is: "sudo apt-get install git-core". Is that it? Do I need to do a git-init as well, or will the ikiwiki-makerepo handle that? If I have to do a git-init as well, what --share values should I specify?
+
+It seems I will have to install the ikiwiki from the tar.gz file. I have downloaded it, but do I need to install CPAN or CPAN++ first? That doesn't sound right. I am totally confused already. Does anyone have some install documents pitched to someone as ignorant as I am? -- [[WillDioneda]]
+
+> Ubuntu includes ikiwiki (in universe, I assume), so you should just be
+> able to use apt or synaptic to install the package, as documented on the
+> [[download]] page. Install git-core also to get git.
+>
+> You do not need to use git-init if you use ikiwiki-makrepo. --[[Joey]]
+
+
+Thanks for your response. You're right. Ubuntu does have ikiwiki, except that it is an older version. I tried installing it; saw some error messages from the install, and decided against it. Plus the documentation here in ikiwiki.info seems slightly different. I made an executive/beginner decision: to go for the latest tarball. And found myself in deep water, ...
+
+Anyway, I think I might be able to install it from the tarball I downloaded. I've been reading the discussions, had a look at your screencasts, etc. I will give it another bash. -- [[WillDioneda]]
+
+----
+
+How do I set up cgi editing? In setup I have:
+
+ * cgiurl => 'http://wiki.had.co.nz/edit.cgi'
+ * cgi_wrapper => 'edit.cgi'
+
+But I don't get an edit link on my pages? What am I doing wrong?
+
+> Assuming you don't have the editpage plugin disabled, all you should need
+> to so is re-run `ikiwiki -setup` with the above config and it should
+> rebuild your wiki and add the edit links to pages. --[[Joey]]
+
+----
+
+I setup ikiwiki on a fedora 10 machine and I am using apache as my http server. Faced a few difficulties while setting it up as the default setup program left some suid files and group writeable directories on the system. It took some time to get it working and documented what I did at http://flyingtux.blogspot.com/2009/03/installing-ikiwiki.html. Thought it might be useful to someone here. (The version installed is 2.72)
+
+> ikiwiki makes wrappers suid by default, because this ensures that when
+> the ikiwiki.cgi is run by your web server, it runs as the user who owns
+> your wiki, and can thus write to it. ikiwiki is designed to run securely
+> suid. If your webserver uses some
+> mechanism to run the ikiwiki.cgi as the user who owns it, without the
+> suid bit being set, you *could* modify `cgi_wrappermode` in your setup
+> file to drop the suid bit.
+>
+> ikiwiki respects the umask, so if your umask is one that causes things to
+> be group writable, they will by. If you want to override that, there is
+> also a `umask ` setting in your setup file. --[[Joey]]
+
+----
+
+/etc/ikiwiki/auto.setup tries to get abs_path of a non-existent
+"repository" path (in ikiwiki-makerepo), and that doesn't work in my perl:
+
+<pre>
+[mort@localhost ~]$ perl -e 'use Cwd q{abs_path}; print abs_path("/var")'
+/var[mort@localhost ~]$ perl -e 'use Cwd q{abs_path}; print abs_path("/abcde")'
+[mort@localhost ~]$
+</pre>
+
+Because of this, /etc/ikiwiki/auto.setup fails:
+
+<pre>
+$ ikiwiki -setup /etc/ikiwiki/auto.setup
+What will the wiki be named? wiki
+What revision control system to use? git
+What wiki user (or openid) will be admin? mort
+
+
+Setting up wiki ...
+internal error finding repository abs_path
+/etc/ikiwiki/auto.setup: failed to set up the repository with ikiwiki-makerepo
+
+usage: ikiwiki [options] source dest
+ ikiwiki --setup configfile
+$ perl -v
+
+This is perl, v5.8.8 built for i386-linux-thread-multi
+(with 2 registered patches, see perl -V for more detail)
+
+Copyright 1987-2007, Larry Wall
+
+Perl may be copied only under the terms of either the Artistic License or the
+GNU General Public License, which may be found in the Perl 5 source kit.
+
+Complete documentation for Perl, including FAQ lists, should be found on
+this system using "man perl" or "perldoc perl". If you have access to the
+Internet, point your browser at http://www.perl.org/, the Perl Home Page.
+
+$
+</pre>
+
+Can't ikiwiki's "make test" perhaps test for this, so that one knows something will go wrong?
+-- Ivan Z.
+
+> FWIW, I tried the same thing with perl 5.8.8 from Debian etch, and its
+> Cwd does not have the problem. But I've modified `ikiwiki-makerepo` to
+> avoid using `abs_path` this way anyhow. --[[Joey]]
+
+Thank you! I'm not a Perl programmer, so what's your opinion: is this behavior a violation of the specification of abs_path and I should report it to [ALTLinux](http://bugs.altlinux.org) (the distro)? --Ivan Z.
+
+> That is not entirely clear to me from the documentation. It doesn't
+> say the path has to exist, but doesn't say it cannot either. --[[Joey]]
* [[!shortcut name=debrt url="https://rt.debian.org/Ticket/Display.html?id=%s"]]
* [[!shortcut name=debss url="http://snapshot.debian.net/package/%s"]]
* Usage: `\[[!debss package]]`, `\[[!debss package#version]]`, or `\[[!debss package/version]]`. See http://snapshot.debian.net for details.
- [[!shortcut name=debwiki url="http://wiki.debian.org/%s"]]
+* [[!shortcut name=debwiki url="http://wiki.debian.org/%s"]]
* [[!shortcut name=fdobug url="https://bugs.freedesktop.org/show_bug.cgi?id=%s" desc="freedesktop.org bug #%s"]]
* [[!shortcut name=fdolist url="http://lists.freedesktop.org/mailman/listinfo/%s" desc="%s@lists.freedesktop.org"]]
* [[!shortcut name=gnomebug url="http://bugzilla.gnome.org/show_bug.cgi?id=%s" desc="GNOME bug #%s"]]
* [[!shortcut name=ohloh url="http://www.ohloh.net/projects/%s"]]
To add a new shortcut, use the `shortcut`
-[[ikiwiki/PreprocessorDirective]]. In the url, "%s" is replaced with the
-text passed to the named shortcut, after url-encoding it, and '%S' is
-replaced with the raw, non-encoded text. The optional `desc` parameter
-controls the description of the link.
+[[ikiwiki/directive]]. In the url, "%s" is replaced with the
+text passed to the named shortcut, after [[!wikipedia url_encoding]]
+it, and '%S' is replaced with the raw, non-encoded text. The optional
+`desc` parameter controls the description of the link.
Remember that the `name` you give the shortcut will become a new
-[[ikiwiki/PreprocessorDirective]]. Avoid using a `name` that conflicts
+[[ikiwiki/directive]]. Avoid using a `name` that conflicts
with an existing directive. These directives also accept a `desc`
parameter that will override the one provided at definition time.
If you come up with a shortcut that you think others might find useful,
consider contributing it to the [shortcuts page on the ikiwiki
-ikiwiki](http://ikiwiki.info/shortcuts/), so that future versions of
+wiki](http://ikiwiki.info/shortcuts/), so that future versions of
ikiwiki will include your shortcut in the standard underlay.
This map excludes discussion pages, as well as subpages that are in feeds.
-[[map pages="* and !*/discussion and !recentchanges
+[[!map pages="* and !*/discussion and !recentchanges
and !bugs/* and !examples/*/* and !news/* and !tips/* and !plugins/*
and !sandbox/* and !todo/* and !users/*
and !*.css and !*.ico and !*.png and !*.svgz and !*.gif"]]
This page is used to control what smileys are supported by the wiki.
Just write the text of a smiley to display it.
-* \:) [[smileys/smile.png]]
-* \:-) [[smileys/smile.png]]
-* \:D [[smileys/biggrin.png]]
-* \:-D [[smileys/biggrin.png]]
-* \B) [[smileys/smile2.png]]
-* \B-) [[smileys/smile2.png]]
-* \:)) [[smileys/smile3.png]]
-* \:-)) [[smileys/smile3.png]]
-* \;) [[smileys/smile4.png]]
-* \;-) [[smileys/smile4.png]]
-* \:\ [[smileys/ohwell.png]]
-* \:-\ [[smileys/ohwell.png]]
-* \:/ [[smileys/ohwell.png]]
-* \:-/ [[smileys/ohwell.png]]
-* \:| [[smileys/neutral.png]]
-* \:-| [[smileys/neutral.png]]
-* \>:> [[smileys/devil.png]]
-* \X-( [[smileys/angry.png]]
-* \<:( [[smileys/frown.png]]
-* \:( [[smileys/sad.png]]
-* \:-( [[smileys/sad.png]]
-* \:-? [[smileys/tongue.png]]
-* \:-P [[smileys/tongue.png]]
-* \:o [[smileys/redface.png]]
-* \|) [[smileys/tired.png]]
-* \|-) [[smileys/tired.png]]
-* \{OK} [[smileys/thumbs-up.png]]
-* \{X} [[smileys/icon-error.png]]
-* \{i} [[smileys/icon-info.png]]
-* \(./) [[smileys/checkmark.png]]
-* \(!) [[smileys/idea.png]]
-* \[!] [[smileys/attention.png]]
-* \/!\ [[smileys/alert.png]]
-* \(?) [[smileys/question.png]]
-* \{*} [[smileys/star_on.png]]
-* \{o} [[smileys/star_off.png]]
-* \{1} [[smileys/prio1.png]]
-* \{2} [[smileys/prio2.png]]
-* \{3} [[smileys/prio3.png]]
+* \\:) [[smileys/smile.png]]
+* \\:-) [[smileys/smile.png]]
+* \\:D [[smileys/biggrin.png]]
+* \\:-D [[smileys/biggrin.png]]
+* \\B) [[smileys/smile2.png]]
+* \\B-) [[smileys/smile2.png]]
+* \\:)) [[smileys/smile3.png]]
+* \\:-)) [[smileys/smile3.png]]
+* \\;) [[smileys/smile4.png]]
+* \\;-) [[smileys/smile4.png]]
+* \\:\ [[smileys/ohwell.png]]
+* \\:-\ [[smileys/ohwell.png]]
+* \\:/ [[smileys/ohwell.png]]
+* \\:-/ [[smileys/ohwell.png]]
+* \\:| [[smileys/neutral.png]]
+* \\:-| [[smileys/neutral.png]]
+* \\>:> [[smileys/devil.png]]
+* \\X-( [[smileys/angry.png]]
+* \\<:( [[smileys/frown.png]]
+* \\:( [[smileys/sad.png]]
+* \\:-( [[smileys/sad.png]]
+* \\:-? [[smileys/tongue.png]]
+* \\:-P [[smileys/tongue.png]]
+* \\:o [[smileys/redface.png]]
+* \\|) [[smileys/tired.png]]
+* \\|-) [[smileys/tired.png]]
+* \\{OK} [[smileys/thumbs-up.png]]
+* \\{X} [[smileys/icon-error.png]]
+* \\{i} [[smileys/icon-info.png]]
+* \\(./) [[smileys/checkmark.png]]
+* \\(!) [[smileys/idea.png]]
+* \\[!] [[smileys/attention.png]]
+* \\/!\ [[smileys/alert.png]]
+* \\(?) [[smileys/question.png]]
+* \\{x} [[smileys/star_on.png]]
+* \\{*} [[smileys/star_on.png]]
+* \\{o} [[smileys/star_off.png]]
+* \\{1} [[smileys/prio1.png]]
+* \\{2} [[smileys/prio2.png]]
+* \\{3} [[smileys/prio3.png]]
-For example: {*} B) {*}
+For example: {x} B) {x}
----
-[[meta title="Summer of Code"]]
+[[!meta title="Summer of Code"]]
This page includes information about ikiwiki's involvement in
[Google Summer of Code](http://code.google.com/soc/).
as a todo item, and ask us if it might work as a Summer of Code project,
but please don't add the `soc` tag yourself.
-[[inline pages="(todo/* or bugs/*) and link(soc) and !todo/done and
+[[!inline pages="(todo/* or bugs/*) and link(soc) and !todo/done and
!link(todo/done) and !bugs/done and !link(bugs/done) and
!*/Discussion" actions=yes show=0]]
display: block;
}
-.author {
+.inlineheader .author {
margin: 0;
font-size: 18px;
font-weight: bold;
margin: 0;
padding: 6px;
list-style-type: none;
+}
+.actions li {
+ display: inline;
+ padding: .2em .4em;
+}
+.pageheader .actions ul {
border-bottom: 1px solid #000;
}
border-bottom: 0;
}
-.actions li {
+#otherlanguages ul {
+ margin: 0;
+ padding: 6px;
+ list-style-type: none;
+}
+#otherlanguages li {
display: inline;
padding: .2em .4em;
}
+.pageheader #otherlanguages {
+ border-bottom: 1px solid #000;
+}
-.tags {
+div.inlinecontent {
+ margin-top: .4em;
+}
+
+.pagefooter {
+ clear: both;
+}
+.inlinefooter {
clear: both;
}
+.tags {
+}
+
#pageinfo {
- clear: both;
margin: 1em 0;
border-top: 1px solid #000;
}
border-style: solid;
border-width: 1px;
overflow: auto;
+ clear: both;
width: 100%;
background: #eee;
color: black !important;
.pagedate,
.pagelicense,
.pagecopyright {
- clear: both;
font-style: italic;
display: block;
margin-top: 1em;
}
+.error {
+ color: #C00;
+}
+
/* Used for invalid form fields. */
.fb_invalid {
color: red;
margin-left: 40px;
margin-bottom: 40px;
padding: 2ex 2ex;
+ background: white;
+ color: black !important;
}
/* outlines */
border: 1px solid #aaa;
}
+div.progress {
+ margin-top: 1ex;
+ margin-bottom: 1ex;
+ border: 1px solid #888;
+ width: 400px;
+ background: #eee;
+ color: black !important;
+ padding: 1px;
+}
+div.progress-done {
+ background: #ea6 !important;
+ color: black !important;
+ text-align: center;
+ padding: 1px;
+}
+
input#openid_url {
background: url(wikiicons/openidlogin-bg.gif) no-repeat;
background-color: #fff;
padding-left: 18px;
}
+input#searchbox {
+ background: url(wikiicons/search-bg.gif) no-repeat;
+ background-color: #fff;
+ background-position: 100% 50%;
+ color: #000;
+ padding-right: 16px;
+}
+
/* Things to hide in printouts. */
@media print {
.actions { display: none; }
margin-bottom: 1ex;
padding: 1ex 1ex;
border: 1px solid #aaa;
+ background: white;
+ color: black !important;
}
/* Provided for use by template plugin for floating note boxes. */
margin-bottom: 1ex;
padding: 1ex 1ex;
border: 1px solid #aaa;
- width: 25%
+ width: 25%;
+ background: white;
+ color: black !important;
}
/* Used by the popup template and for backlinks hiding. */
border: 2px solid;
background-color: #dee;
color: black;
-
- /* Nonstandard, but very nice. */
- opacity: 0.95;
- -moz-opacity: 0.95;
- filter: alpha(opacity=95);
}
/* Formbuilder styling */
background: #eee;
color: black !important;
}
+
+span.color {
+ padding: 2px;
+}
+
+.comment-header,
+.microblog-header {
+ font-style: italic;
+ margin-top: .3em;
+}
+.comment .author,
+.microblog .author {
+ font-weight: bold;
+}
+.comment-subject {
+ font-weight: bold;
+}
+.comment {
+ border: 1px solid #aaa;
+ padding: 3px;
+}
+
+/* Used by the highlight plugin. */
+
+pre.hl { color:#000000; background-color:#ffffff; }
+.hl.num { color:#2928ff; }
+.hl.esc { color:#ff00ff; }
+.hl.str { color:#ff0000; }
+.hl.dstr { color:#818100; }
+.hl.slc { color:#838183; font-style:italic; }
+.hl.com { color:#838183; font-style:italic; }
+.hl.dir { color:#008200; }
+.hl.sym { color:#000000; }
+.hl.line { color:#555555; }
+.hl.mark { background-color:#ffffbb; }
+.hl.kwa { color:#000000; font-weight:bold; }
+.hl.kwb { color:#830000; }
+.hl.kwc { color:#000000; font-weight:bold; }
+.hl.kwd { color:#010181; }
Generally you will tag a page without putting a visible link on it.
The [[tag_plugin|plugins/tag]] allows you to do so, like this:
- \[[tag mytag othertag thirdtag]]
+ \[[!tag mytag othertag thirdtag]]
You can also tag a page with a visible link:
- \[[taglink mytag]]
+ \[[!taglink mytag]]
This tag will be displayed just like a regular [[ikiwiki/WikiLink]].
-One way to use these tags is to create a [[ikiwiki/blog]] of pages that have a
+One way to use these tags is to create a [[blog]] of pages that have a
particular set of tags. Or just look at the [[BackLinks]] to a tag page to
see all the pages that are tagged with it. [[Plugins]] can be written to do
anything else with tags that you might desire.
In another blog, I could tag a post with arbitrary words and not have to do
anything else for the software to recognize it as a tag. In Ikiwiki if you
-want to tag something \[[tag foo]] you also have to go to tags/ and create
+want to tag something \[[!tag foo]] you also have to go to tags/ and create
foo.mkdn (even if it's zero-length), because "tags are links", and links
don't actually *link* if they have no destination. This allows for
customization of how you present different tag feeds, but this (to me) is
[[!if test="enabled(template) and enabled(inline)" then="""
-## Available templates
-
These templates are available for inclusion onto other pages in this
wiki:
documentation for the full syntax, but all you really need to know are a
few things:
+* Each parameter you pass to the template directive will generate a
+ template variable. There are also some pre-defined variables like PAGE
+ and BASENAME.
* To insert the value of a variable, use `<TMPL_VAR variable>`. Wiki markup
in the value will first be converted to html.
* To insert the raw value of a variable, with wiki markup not yet converted
Here's a sample template:
<span class="infobox">
- Name: [[<TMPL_VAR raw_name>]]<br />
+ Name: \[[<TMPL_VAR raw_name>]]<br />
Age: <TMPL_VAR age><br />
<TMPL_IF NAME="color">
Favorite color: <TMPL_VAR color><br />
markup in the template. Note though that such WikiLinks will not show up as
backlinks to the page that uses the template.
-Note the use of "raw_name" inside the [[WikiLink]] generator. This ensures
-that if the name contains something that might be mistaken for wiki markup,
-it's not converted to html before being processed as a [[WikiLink]].
+Note the use of "raw_name" inside the [[ikiwiki/WikiLink]] generator. This
+ensures that if the name contains something that might be mistaken for wiki
+markup, it's not converted to html before being processed as a
+[[ikiwiki/WikiLink]].
--- /dev/null
+This confuses me enormously. Perhaps because I am new to ikiwiki, to perl, to Linux, etc.
+
+note and popups are templates? But they're not in the templates directory, and in my readings here, templates are supposed to be in the ../templates directory.
+
+> Ikiwiki has an basewiki underlay that provides wiki files not included in
+> your personal wiki sources. The note and popup template pages are
+> installed there, typically in `/usr/share/ikiwiki/basewiki/templates/`
+> --[[Joey]]
--- /dev/null
+<span class="infobox">
+Available in a [[!taglink /git]] repository.<br />
+Branch: <TMPL_VAR branch><br />
+Author: <TMPL_VAR author><br />
+</span>
+<TMPL_UNLESS NAME="branch">
+This template is used to create an infobox for a git branch. It uses
+these parameters:
+
+<ul>
+<li>branch - the name of the branch, prefixed with the name of one of the
+ remotes listed on the [[/git]] page and provided by the gitremotes script
+ (e.g. github/master)</li>
+<li>author - the author of the branch</li>
+</ul>
+
+It also automatically tags the branch with `/git`.
+</TMPL_UNLESS>
<span class="infobox">
Plugin: <TMPL_VAR name><br />
Author: <TMPL_VAR author><br />
-Included in ikiwiki: [[if test="sourcepage(plugins/contrib/*)" then="""no""" else="""yes"""]]<br />
+Included in ikiwiki: [[!if test="sourcepage(plugins/contrib/*)" then="""no""" else="""yes"""]]<br />
Enabled by default: <TMPL_IF core>yes<TMPL_ELSE>no</TMPL_IF><br />
-Included in [[/plugins/goodstuff]]: [[if test="backlink(plugins/goodstuff)" all=no then="""yes""" else="""no"""]]<br />
-Currently enabled: [[if test="enabled(<TMPL_VAR name>)" then="yes" else="no"]]<br />
+Included in [[/plugins/goodstuff]]: [[!if test="backlink(plugins/goodstuff)" all=no then="""yes""" else="""no"""]]<br />
+Currently enabled: [[!if test="enabled(<TMPL_VAR name>)" then="yes" else="no"]]<br />
</span>
-[[if test="sourcepage(plugins/contrib/*)" then="""[[meta title="<TMPL_VAR name> (third party plugin)"]]"""]]
-<TMPL_IF core>[[tag plugins/type/core]]</TMPL_IF>
+[[!if test="sourcepage(plugins/contrib/*)" then="""[[!meta title="<TMPL_VAR name> (third party plugin)"]]"""]]
+<TMPL_IF core>[[!tag plugins/type/core]]</TMPL_IF>
<TMPL_UNLESS NAME="name">
This template is used to create an infobox for an ikiwiki plugin. It uses
these parameters:
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=joey%40kitenet%2enet&item_name=ikiwiki&no_shipping=1&cn=Comments%3f&tax=0¤cy_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8"><img src="https://www.paypal.com/en_US/i/btn/x-click-but04.gif" alt="donate with PayPal" /></a>
-If you would like your donation listed here, let [[Joey]] know. Thanks to
-the following people for their kind contributions:
+Thanks to the following people for their kind contributions:
* James Westby
* Kyle S MacLea
* Adam Shand
* Martin Krafft
+* Paweł Tęcza
+* Mick Pollard
-(Note that this page is locked to prevent anyone from tampering with the PayPal button.)
+(Note that this page is locked to prevent anyone from tampering with the PayPal button.
+If you prefer your donation *not* be listed here, let [[Joey]] know.)
This page is a place to document tips and techniques for using ikiwiki.
-[[inline pages="tips/* and !tips/*/*"
+[[!inline pages="tips/* and !tips/*/*"
feedpages="created_after(tips/howto_avoid_flooding_aggregators)" archive="yes"
rootpage="tips" postformtext="Add a new tip about:" show=0]]
--- /dev/null
+<a href="http://disqus.com">Disqus</a> is a comment system that you can add to your blog to manage comments.
+
+To add it to ikiwiki first create an account at disqus and add you blog. Then click on the Admin link at that top of the main page.
+
+In the admin section there should be a tab called "Tools" for you site. Select the "Generic Code" option to install your site and then tweak the settings so the comments box looks like you want. This will then create a bit of javascript. Copy that code.
+
+In ikiwiki templates edit the page.tmpl and somewhere down the bottom, I put mine just before the footer, paste in the code that you had from before. This will add a disqus comment box to every page on your site.
+
+If you want to change your blog to also use the comments then you need to edit the inlinepage.tmpl template as well. This time remove the lines
+
+ <TMPL_IF NAME="DISCUSSIONLINK">
+ <li><TMPL_VAR DISCUSSIONLINK></li>
+
+and replace with
+
+ <li>
+ <TMPL_IF NAME="PERMALINK">
+ <a href="<TMPL_VAR PERMALINK>">Comment</a>
+ <TMPL_ELSE>
+ <a href="<TMPL_VAR PAGEURL>">Comment</a>
+ </TMPL_IF>
+ </li>
+
+This changes the discussion link to a Comment link that takes you to the full page for that blog entry which should contain the disqus comments form that you added before.
+
+Note: This does then mean that to add a comment people need to have javascript enabled.
In your .bashrc/.bash_profile/.profile, add:
- export PERL5LIB=~/site/perl/share/perl/5.8:~/site/perl/share/perl/5.8.4:~/site/perl/lib/perl5:~/site/perl/lib/perl/5.8.4
+ export PERL5LIB="$HOME/site/perl/share/perl/5.8:$HOME/site/perl/share/perl/5.8.4:$HOME/site/perl/lib/perl5:$HOME/site/perl/lib/perl/5.8.4"
+
+These locations may be different on your computer. For example, I use:
+
+ export PERL5LIB="$HOME/site/perl/lib/perl5:$HOME/site/perl/lib/perl5/site_perl/5.8.8:$PERL5LIB"
You probably want to add *~/site/perl/bin/* to your path, as well, since Ikiwiki's scripts are put in there.
[good]$ ls -la ~
lrwxrwxrwx 1 root staff 25 2007-08-03 16:44 /home/user -> /home/.server/user
-So far, it looks like only the source and destination parameters require this unsymlinked path, but for paranoia reasons, you may want to put them everywhere. [[news/version_2.14]] explains why this happens.
+So far, it looks like only the source and destination parameters require this unsymlinked path, but for paranoia reasons, you may want to put them everywhere. The changelog for version 2.14 explains why this happens.
Next, add your installed Perl module directory to the *libdir* parameter. It should look something like :
libdir => "/home/.server/user/site/perl/lib/perl5/",
# CGI Wrapper
+The CGI wrapper file will be created automatically by "ikiwiki --setup path/to/setup", as long as you have inserted a valid filename to be created into the setup file. On DreamHost, be careful not to put the ikiwiki.cgi file in a directory that has different owner/group than the file itself (such as the main site.domain.tld/ directory): this will cause suexec to fail.
+
The wrapper mode of "06755" doesn't seem to work. "755" appears to. However, this may be completely insecure and/or buggy, so if you know better than I, edit this doc and add it here.
# Pre-created SVN repository
I managed to install ikiwiki on eggplant farms, with most basic features except markdown.
I think ikiwiki is more suitable for VPS/dedicated server. Shared hosting doesn't fit.
+
+I just (2009/04/27) installed ikiwiki on DreamHost and the CPAN instructions here are unnecessarily complicated. I used "cpan" instead of "perl -MCPAN -e shell" and had no trouble with that portion of the install. --[[schmonz]]
+
+After tiring of managing things by hand, I've switched to using
+pkgsrc as an unprivileged user. This uses a bit more disk for my
+own copies of perl, python, etc., but in exchange I can `cd
+.../pkgsrc/www/ikiwiki && make install` and everything just works.
+Plus I get all the benefits of a package system, like easy uninstalling
+and being notified of outdated or insecure software.
+
+The only catch: sometimes the package dependency tree gets too deep
+for DreamHost's user process limit, resulting in build death. I
+work around this by resuming the build partway down the tree, then
+trying again from whatever I was actually trying to install.
+--[[schmonz]]
--- /dev/null
+One may want to provide ikiwiki hosting with [[rcs/git]]+ssh access and web
+server located at different hosts. Here's a description for such
+a setup, using password-less SSH as a way of communication between
+these two hosts.
+
+Git server
+==========
+
+Let's create a user called `ikiwiki_example`. This user gets SSH
+access restricted to GIT pull/push, using `git-shell` as a shell.
+
+The root (bare) repository:
+
+- is stored in `~ikiwki_example/ikiwiki_example.git`
+- is owned by `ikiwiki_example:ikiwiki_example`
+- has permissions 0700
+
+The master repository's post-update hook connects via SSH to
+`webserver` as user `ikiwiki_example`, in order to run
+`~/bin/ikiwiki.update` on `webserver`; this post-update hook, located
+in `~ikiwki_example/ikiwiki_example.git/hooks/post-update`, is
+executable and contains:
+
+ #!/bin/sh
+ /usr/bin/ssh ikiwiki_example@webserver bin/ikiwiki.update
+
+Password-less SSH must be setup to make this possible; one can
+restrict `gitserver:ikiwiki_example` to be able to run only the needed
+command on the web server, using such a line in
+`webserver:~ikiwiki_example/.ssh/authorized_keys`:
+
+ command="bin/ikiwiki.update",from="gitserver.example.com",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa ...
+
+Web server
+==========
+
+Let's create a user called `ikiwiki_example` on `webserver`. She needs
+to have write permission to the destination directory.
+
+The working tree repository (`srcdir`):
+
+- is stored in `~ikiwki_example/src`
+- is owned by `ikiwiki_example:ikiwiki_example`
+- has permissions 0700
+- has the following origin: `ikiwiki_example@gitserver:ikiwiki_example.git`
+
+The CGI wrapper is generated with ownership set to
+`ikiwiki_example:ikiwiki_example` and permissions `06755`.
+
+Password-less SSH must be setup so that `ikiwiki_example@webserver` is
+allowed to push to the master repository. As told earlier, SSH access
+to `ikiwiki_example@gitserver` is restricted to GIT pull/push, which
+is just what we need.
+
+The Git wrapper is generated in `~ikiwiki_example/bin/ikiwiki.update`:
+
+ git_wrapper => '/home/ikiwiki_example/bin/ikiwiki.update'
+
+As previously explained, this wrapper is run over SSH by the master
+repository's post-update hook; it pulls updates from the master
+repository and triggers a wiki refresh.
Once you've created your "custom search engine", just drop in the search box html like I've done in my [Debian tips and tricks](http://dabase.com/tips/) [source](http://git.webconverger.org/?p=faq.git;a=blob;f=tips.mdwn).
If you have odd "save failed" error messages in Google's CSE's control panel, try `/usr/lib/WebKit/GtkLauncher` from [webkit](http://packages.qa.debian.org/w/webkit.html).
+
+
+# Alternatively
+
+You could use the [[Google_plugin|plugins/google]] from version 2.67.
[This](http://git.chris-lamb.co.uk/?p=ikiwiki-wordpress-import.git) is a simple tool that generates [git-fast-import](http://www.kernel.org/pub/software/scm/git/docs/git-fast-import.html)-compatible data from a WordPress export XML file. It retains creation time of each post, so you can use Ikiwiki's <tt>--getctime</tt> to get the preserve creation times on checkout.
-WordPress categories are mapped onto Ikiwiki tags. The ability to import comments is planned.
\ No newline at end of file
+WordPress categories are mapped onto Ikiwiki tags. The ability to import comments is planned.
+
+-----
+
+I include a modified version of this script. This version includes the ability to write \[[!tag foo]] directives, which the original intended, but didn't actually do.
+
+-- [[users/simonraven]]
+
+[[ikiwiki-wordpress-import]]
--- /dev/null
+When I attempt to use this script, I get the following error:
+warning: Not updating refs/heads/master (new tip 26b1787fca04f2f9772b6854843fe99fe06e6088 does not contain fc0ad65d14d88fd27a6cee74c7cef3176f6900ec). I have git 1.5.6.5, any ideas?
+
+Thanks!!
+
+-----
+
+### KeyError: 146
+
+I also get this error, here's the output (it seems to stem from an error in the python script):
+
+<pre>
+Traceback (most recent call last):
+ File "../ikiwiki-wordpress-import.py", line 74, in <module>
+ main(*sys.argv[1:])
+ File "../ikiwiki-wordpress-import.py", line 54, in main
+ data = content.encode('ascii', 'html_replace')
+ File "../ikiwiki-wordpress-import.py", line 30, in <lambda>
+ % htmlentitydefs.codepoint2name[ord(c)] for c in x.object[x.start:x.end]]), x.end))
+KeyError: 146
+warning: Not updating refs/heads/master (new tip 6dca6ac939e12966bd64ce8a822ef14fe60622b2 does not contain 60b798dbf92ec5ae92f18acac3075c4304aca120)
+git-fast-import statistics:
+</pre>
+
+etc.
+
+(Removed now dead info and blah blah.)
+
+> It works fine.... The script is picky about having everything in proper UTF-8, **and** proper XML and HTML escaping. You need that to have a successful import. I let Emacs remove DOS line endings, and it works OK (if on *nix of some sort, of course). Thing is with this `git fast-import`, is that you have to `git reset` afterwards, (let's say you put them in posts/) `git checkout posts`, `git add posts`, then commit. I don't know if this a characteristic with `git fast-import`, but this is the way I get my posts to exist on the filesystem. If I don't do this, then I lose the data. If you get that "Not updating..." error, then just --force the import in. --[[users/simonraven]]
--- /dev/null
+If you use twitter or identi.ca, here's how to make a box
+on the side of your blog that holds your recent status updates
+from there, like I have on [my blog](http://kitenet.net/~joey/blog/)
+--[[Joey]]
+
+* Enable the [[plugins/aggregate]] plugin, and set up a cron
+ job for it.
+* At the top of your blog's page, add something like the following.
+ You'll want to change the urls of course. Be sure to also change
+ the inline directive's [[PageSpec]] to link to the location the
+ feed is aggregated to, which will be a subpage of the page
+ you put this on (blog in this example):
+
+ \[[!template id=note text="""
+ \[[!aggregate expirecount=5 name="dents" url="http://identi.ca/joeyh"
+ feedurl="http://identi.ca/api/statuses/user_timeline/joeyh.atom"]]
+ \[[!inline pages="internal(./blog/dents/*)" template=microblog
+ show=5 feeds=no]]
+ """]]
+
+Note: Works best with ikiwiki 3.10 or better.
--- /dev/null
+The example you gave looks a bit odd.
+
+This is what I did from your example (still trying to learn the more complex things ;).
+
+<pre>
+\[[!template id=note text="""
+\[[!aggregate expirecount=5 name=kijkaqawej url=http://identi.ca/kjikaqawej
+feedurl=http://identi.ca/api/statuses/user_timeline/kjikaqawej.atom]]
+\[[!inline pages="internal(kijkaqawej/*)" template=microblog show=5 feeds=no]] """]]
+</pre>
+
+mine, live, here: <http://simonraven.kisikew.org/blog/meta/microblog-feed/>
+
+I expected something like: sidebar, with a number, and displaying them in the sidebar, but they don't display (similar to what you have on your blog).
+
+On the [[/ikiwiki/pagespec]] page, it says "internal" pages aren't "first-class" wiki pages, so it's best not to directly display them, so how do you manage to display them? I'd like to display their name, and what they link to in the sidebar, or otherwise in the main body.
+
+> That's what the inline does, displays the internal pages.
+>
+> You need to fix your pagespec to refer to where the pages are aggregated
+> to, under the page that contains the aggregate directive. In your example,
+> it should be `internal(./blog/meta/microblog-feed/kijkaqawej/*)` --[[Joey]]
+
+>> Oooh, I see, it's referring to an absolute path (relative to the site), right?
+>> Thanks :).
+
+>>> Right, PageSpecs are always absolute paths unless prefixed with `./`
+>>> (somewhat confusingly since WikiLinks are always realtive unless
+>>> previxed with `/` ...) --[[Joey]]
+
+>> This is not working for me at all, all I get is some SHA1 hash all the time. I've tried variants of the `internal()` arg, and nothing gets spit out. --[[simonraven]]
+
+>>> Sounds like [[!debbug 380212]]?
+>>> If so, the fix is to use Text::Markdown, or markdown 1.0.2 instead of buggy
+>>> old markdown 1.0.1. --[[Joey]]
+
+>> `ii libtext-markdown-perl 1.0.21-1 Markdown and MultiMarkdown markup languages library`
+>>
+>> I'm using `Text::Markdown` due to its "multi-markdown" support. Yes, it does seem exactly like [[!debbug 380212]] .
+>> Maybe update it from CPAN + dh-make-perl (if there's a new one, that is) --[[simonraven]]
+>> I've just built and installed `libtext-markdown-perl 1.0.21-1` from dh-make-perl & CPAN, and regenerated that page.. let's see what happens... no hashes, but nothing else either:
+>>
+>> "kijkaqawej: last checked 10 minutes ago (25 posts)" -- inside of a box, no display of posts.
+++ /dev/null
-Many ikiwiki examples name the [[cgi]] "ikiwiki.cgi", and put it somewhere
-like `~/public_html/ikiwiki.cgi`, or `/var/www/wiki/ikiwiki.cgi`.
-
-If you follow those examples, you may find that when trying to edit a page
-in your wiki, you see the raw contents of the ikiwiki.cgi program. Or get a
-permission denied problem.
-
-This is because apache is generally not configured to run cgi scripts
-unless they're in `/usr/lib/cgi-bin/`. While you can put ikiwiki.cgi in
-there if you like, here's how to configure apache (version 2) to run `.cgi`
-programs from anywhere.
-
-These instructions are for Debian systems, but the basic apache
-configuration should work anywhere.
-
-* Edit /etc/apache2/apache2.conf and add a line like this:
-
- AddHandler cgi-script .cgi
-
-* Find the "Options" line for the directory where you've put the
- ikiwiki.cgi, and add "ExecCGI" to the list of options. For example, if
- ikiwiki.cgi is in /var/www/, edit `/etc/apache2/sites-enabled/000-default`
- and add it to the "Options" line in the "Directory /var/www/" stanza.
- Or, if you've put it in a `~/public_html`, edit
- `/etc/apache2/mods-available/userdir.conf`.
-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.
--- /dev/null
+You've enabled the [[plugins/comments]] plugin, so a set of pages on your
+blog can have comments added to them. Pages with comments even have special
+feeds that can be used to subscribe to those comments. But you'd like to
+add a feed that contains all the comments posted to any page. Here's how:
+
+ \[[!inline pages="internal(*/comment_*)" template=comment]]
+
+The special [[ikiwiki/PageSpec]] matches all comments. The
+[[template|wikitemplates]] causes the comments to be displayed formatted
+nicely.
--- /dev/null
+[[JoshTriplett]] has developed scripts to convert MoinMoin and TWiki wikis
+to ikiwikis backed by a git repository, including full history. For
+details, see [[his_user_page|JoshTriplett]].
--- /dev/null
+[[sabr]] explains how to [import MediaWiki content into
+git](http://u32.net/Mediawiki_Conversion/index.html?updated), including
+full edit hostory. The [[plugins/contrib/mediawiki]] plugin can then be
+used by ikiwiki to build the wiki.
--- /dev/null
+The u32 page is excellent, but I wonder if documenting the procedure here
+would be worthwhile. Who knows, the remote site might disappear. But also
+there are some variations on the approach that might be useful:
+
+ * using a python script and the dom library to extract the page names from
+ Special:Allpages (such as
+ <http://www.staff.ncl.ac.uk/jon.dowland/unix/docs/get_pagenames.py>)
+ * Or, querying the mysql back-end to get the names
+ * using WWW::MediaWiki for importing/exporting pages from the wiki, instead
+ of Special::Export
+
+Also, some detail on converting mediawiki transclusion to ikiwiki inlines...
+
+-- [[users/Jon]]
+
+> "Who knows, the remote site might disappear.". Right now, it appears to
+> have done just that. -- [[users/Jon]]
+
+
+The iki-fast-load ruby script from the u32 page is given below:
+
+ #!/usr/bin/env ruby
+
+ # This script is called on the final sorted, de-spammed revision
+ # XML file.
+ #
+ # It doesn't currently check for no-op revisions... I believe
+ # that git-fast-load will dutifully load them even though nothing
+ # happened. I don't care to solve this by adding a file cache
+ # to this script. You can run iki-diff-next.rb to highlight any
+ # empty revisions that need to be removed.
+ #
+ # This turns each node into an equivalent file.
+ # It does not convert spaces to underscores in file names.
+ # This would break wikilinks.
+ # I suppose you could fix this with mod_speling or mod_rewrite.
+ #
+ # It replaces nodes in the Image: namespace with the files themselves.
+
+
+ require 'rubygems'
+ require 'node-callback'
+ require 'time'
+ require 'ostruct'
+
+
+ # pipe is the stream to receive the git-fast-import commands
+ # putfrom is true if this branch has existing commits on it, false if not.
+ def format_git_commit(pipe, f)
+ # Need to escape backslashes and double-quotes for git?
+ # No, git breaks when I do this.
+ # For the filename "path with \\", git sez: bad default revision 'HEAD'
+ # filename = '"' + filename.gsub('\\', '\\\\\\\\').gsub('"', '\\"') + '"'
+
+ # In the calls below, length must be the size in bytes!!
+ # TODO: I haven't figured out how this works in the land of UTF8 and Ruby 1.9.
+ pipe.puts "commit #{f.branch}"
+ pipe.puts "committer #{f.username} <#{f.email}> #{f.timestamp.rfc2822}"
+ pipe.puts "data #{f.message.length}\n#{f.message}\n"
+ pipe.puts "from #{f.branch}^0" if f.putfrom
+ pipe.puts "M 644 inline #{f.filename}"
+ pipe.puts "data #{f.content.length}\n#{f.content}\n"
+ pipe.puts
+ end
+
+> Would be nice to know where you could get "node-callbacks"... this thing is useless without it. --[[users/simonraven]]
+
+
+Mediawiki.pm - A plugin which supports mediawiki format.
+
+ #!/usr/bin/perl
+ # By Scott Bronson. Licensed under the GPLv2+ License.
+ # Extends Ikiwiki to be able to handle Mediawiki markup.
+ #
+ # To use the Mediawiki Plugin:
+ # - Install Text::MediawikiFormat
+ # - Turn of prefix_directives in your setup file.
+ # (TODO: we probably don't need to do this anymore?)
+ # prefix_directives => 1,
+ # - Add this plugin on Ikiwiki's path (perl -V, look for @INC)
+ # cp mediawiki.pm something/IkiWiki/Plugin
+ # - And enable it in your setup file
+ # add_plugins => [qw{mediawiki}],
+ # - Finally, turn off the link plugin in setup (this is important)
+ # disable_plugins => [qw{link}],
+ # - Rebuild everything (actually, this should be automatic right?)
+ # - Now all files with a .mediawiki extension should be rendered properly.
+
+
+ package IkiWiki::Plugin::mediawiki;
+
+ use warnings;
+ use strict;
+ use IkiWiki 2.00;
+ use URI;
+
+
+ # This is a gross hack... We disable the link plugin so that our
+ # linkify routine is always called. Then we call the link plugin
+ # directly for all non-mediawiki pages. Ouch... Hopefully Ikiwiki
+ # will be updated soon to support multiple link plugins.
+ require IkiWiki::Plugin::link;
+
+ # Even if T:MwF is not installed, we can still handle all the linking.
+ # The user will just see Mediawiki markup rather than formatted markup.
+ eval q{use Text::MediawikiFormat ()};
+ my $markup_disabled = $@;
+
+ # Work around a UTF8 bug in Text::MediawikiFormat
+ # http://rt.cpan.org/Public/Bug/Display.html?id=26880
+ unless($markup_disabled) {
+ no strict 'refs';
+ no warnings;
+ *{'Text::MediawikiFormat::uri_escape'} = \&URI::Escape::uri_escape_utf8;
+ }
+
+ my %metaheaders; # keeps track of redirects for pagetemplate.
+ my %tags; # keeps track of tags for pagetemplate.
+
+
+ sub import { #{{{
+ hook(type => "checkconfig", id => "mediawiki", call => \&checkconfig);
+ hook(type => "scan", id => "mediawiki", call => \&scan);
+ hook(type => "linkify", id => "mediawiki", call => \&linkify);
+ hook(type => "htmlize", id => "mediawiki", call => \&htmlize);
+ hook(type => "pagetemplate", id => "mediawiki", call => \&pagetemplate);
+ } # }}}
+
+
+ sub checkconfig
+ {
+ return IkiWiki::Plugin::link::checkconfig(@_);
+ }
+
+
+ my $link_regexp = qr{
+ \[\[(?=[^!]) # beginning of link
+ ([^\n\r\]#|<>]+) # 1: page to link to
+ (?:
+ \# # '#', beginning of anchor
+ ([^|\]]+) # 2: anchor text
+ )? # optional
+
+ (?:
+ \| # followed by '|'
+ ([^\]\|]*) # 3: link text
+ )? # optional
+ \]\] # end of link
+ ([a-zA-Z]*) # optional trailing alphas
+ }x;
+
+
+ # Convert spaces in the passed-in string into underscores.
+ # If passed in undef, returns undef without throwing errors.
+ sub underscorize
+ {
+ my $var = shift;
+ $var =~ tr{ }{_} if $var;
+ return $var;
+ }
+
+
+ # Underscorize, strip leading and trailing space, and scrunch
+ # multiple runs of spaces into one underscore.
+ sub scrunch
+ {
+ my $var = shift;
+ if($var) {
+ $var =~ s/^\s+|\s+$//g; # strip leading and trailing space
+ $var =~ s/\s+/ /g; # squash multiple spaces to one
+ }
+ return $var;
+ }
+
+
+ # Translates Mediawiki paths into Ikiwiki paths.
+ # It needs to be pretty careful because Mediawiki and Ikiwiki handle
+ # relative vs. absolute exactly opposite from each other.
+ sub translate_path
+ {
+ my $page = shift;
+ my $path = scrunch(shift);
+
+ # always start from root unless we're doing relative shenanigans.
+ $page = "/" unless $path =~ /^(?:\/|\.\.)/;
+
+ my @result = ();
+ for(split(/\//, "$page/$path")) {
+ if($_ eq '..') {
+ pop @result;
+ } else {
+ push @result, $_ if $_ ne "";
+ }
+ }
+
+ # temporary hack working around http://ikiwiki.info/bugs/Can__39__t_create_root_page/index.html?updated
+ # put this back the way it was once this bug is fixed upstream.
+ # This is actually a major problem because now Mediawiki pages can't link from /Git/git-svn to /git-svn. And upstream appears to be uninterested in fixing this bug. :(
+ # return "/" . join("/", @result);
+ return join("/", @result);
+ }
+
+
+ # Figures out the human-readable text for a wikilink
+ sub linktext
+ {
+ my($page, $inlink, $anchor, $title, $trailing) = @_;
+ my $link = translate_path($page,$inlink);
+
+ # translate_path always produces an absolute link.
+ # get rid of the leading slash before we display this link.
+ $link =~ s#^/##;
+
+ my $out = "";
+ if($title) {
+ $out = IkiWiki::pagetitle($title);
+ } else {
+ $link = $inlink if $inlink =~ /^\s*\//;
+ $out = $anchor ? "$link#$anchor" : $link;
+ if(defined $title && $title eq "") {
+ # a bare pipe appeared in the link...
+ # user wants to strip namespace and trailing parens.
+ $out =~ s/^[A-Za-z0-9_-]*://;
+ $out =~ s/\s*\(.*\)\s*$//;
+ }
+ # A trailing slash suppresses the leading slash
+ $out =~ s#^/(.*)/$#$1#;
+ }
+ $out .= $trailing if defined $trailing;
+ return $out;
+ }
+
+
+ sub tagpage ($)
+ {
+ my $tag=shift;
+
+ if (exists $config{tagbase} && defined $config{tagbase}) {
+ $tag=$config{tagbase}."/".$tag;
+ }
+
+ return $tag;
+ }
+
+
+ # Pass a URL and optional text associated with it. This call turns
+ # it into fully-formatted HTML the same way Mediawiki would.
+ # Counter is used to number untitled links sequentially on the page.
+ # It should be set to 1 when you start parsing a new page. This call
+ # increments it automatically.
+ sub generate_external_link
+ {
+ my $url = shift;
+ my $text = shift;
+ my $counter = shift;
+
+ # Mediawiki trims off trailing commas.
+ # And apparently it does entity substitution first.
+ # Since we can't, we'll fake it.
+
+ # trim any leading and trailing whitespace
+ $url =~ s/^\s+|\s+$//g;
+
+ # url properly terminates on > but must special-case >
+ my $trailer = "";
+ $url =~ s{(\&(?:gt|lt)\;.*)$}{ $trailer = $1, ''; }eg;
+
+ # Trim some potential trailing chars, put them outside the link.
+ my $tmptrail = "";
+ $url =~ s{([,)]+)$}{ $tmptrail .= $1, ''; }eg;
+ $trailer = $tmptrail . $trailer;
+
+ my $title = $url;
+ if(defined $text) {
+ if($text eq "") {
+ $text = "[$$counter]";
+ $$counter += 1;
+ }
+ $text =~ s/^\s+|\s+$//g;
+ $text =~ s/^\|//;
+ } else {
+ $text = $url;
+ }
+
+ return "<a href='$url' title='$title'>$text</a>$trailer";
+ }
+
+
+ # Called to handle bookmarks like [[#heading]] or <span class="createlink"><a href="http://u32.net/cgi-bin/ikiwiki.cgi?page=%20text%20&from=Mediawiki_Plugin%2Fmediawiki&do=create" rel="nofollow">?</a>#a</span>
+ sub generate_fragment_link
+ {
+ my $url = shift;
+ my $text = shift;
+
+ my $inurl = $url;
+ my $intext = $text;
+ $url = scrunch($url);
+
+ if(defined($text) && $text ne "") {
+ $text = scrunch($text);
+ } else {
+ $text = $url;
+ }
+
+ $url = underscorize($url);
+
+ # For some reason Mediawiki puts blank titles on all its fragment links.
+ # I don't see why we would duplicate that behavior here.
+ return "<a href='$url'>$text</a>";
+ }
+
+
+ sub generate_internal_link
+ {
+ my($page, $inlink, $anchor, $title, $trailing, $proc) = @_;
+
+ # Ikiwiki's link link plugin wrecks this line when displaying on the site.
+ # Until the code highlighter plugin can turn off link finding,
+ # always escape double brackets in double quotes: [[
+ if($inlink eq '..') {
+ # Mediawiki doesn't touch links like [[..#hi|ho]].
+ return "[[" . $inlink . ($anchor?"#$anchor":"") .
+ ($title?"|$title":"") . "]]" . $trailing;
+ }
+
+ my($linkpage, $linktext);
+ if($inlink =~ /^ (:?) \s* Category (\s* \: \s*) ([^\]]*) $/x) {
+ # Handle category links
+ my $sep = $2;
+ $inlink = $3;
+ $linkpage = IkiWiki::linkpage(translate_path($page, $inlink));
+ if($1) {
+ # Produce a link but don't add this page to the given category.
+ $linkpage = tagpage($linkpage);
+ $linktext = ($title ? '' : "Category$sep") .
+ linktext($page, $inlink, $anchor, $title, $trailing);
+ $tags{$page}{$linkpage} = 1;
+ } else {
+ # Add this page to the given category but don't produce a link.
+ $tags{$page}{$linkpage} = 1;
+ &$proc(tagpage($linkpage), $linktext, $anchor);
+ return "";
+ }
+ } else {
+ # It's just a regular link
+ $linkpage = IkiWiki::linkpage(translate_path($page, $inlink));
+ $linktext = linktext($page, $inlink, $anchor, $title, $trailing);
+ }
+
+ return &$proc($linkpage, $linktext, $anchor);
+ }
+
+
+ sub check_redirect
+ {
+ my %params=@_;
+
+ my $page=$params{page};
+ my $destpage=$params{destpage};
+ my $content=$params{content};
+
+ return "" if $page ne $destpage;
+
+ if($content !~ /^ \s* \#REDIRECT \s* \[\[ ( [^\]]+ ) \]\]/x) {
+ # this page isn't a redirect, render it normally.
+ return undef;
+ }
+
+ # The rest of this function is copied from the redir clause
+ # in meta::preprocess and actually handles the redirect.
+
+ my $value = $1;
+ $value =~ s/^\s+|\s+$//g;
+
+ my $safe=0;
+ if ($value !~ /^\w+:\/\//) {
+ # it's a local link
+ my ($redir_page, $redir_anchor) = split /\#/, $value;
+
+ add_depends($page, $redir_page);
+ my $link=bestlink($page, underscorize(translate_path($page,$redir_page)));
+ if (! length $link) {
+ return "<b>Redirect Error:</b> <nowiki>[[$redir_page]] not found.</nowiki>";
+ }
+
+ $value=urlto($link, $page);
+ $value.='#'.$redir_anchor if defined $redir_anchor;
+ $safe=1;
+
+ # redir cycle detection
+ $pagestate{$page}{mediawiki}{redir}=$link;
+ my $at=$page;
+ my %seen;
+ while (exists $pagestate{$at}{mediawiki}{redir}) {
+ if ($seen{$at}) {
+ return "<b>Redirect Error:</b> cycle found on <nowiki>[[$at]]</nowiki>";
+ }
+ $seen{$at}=1;
+ $at=$pagestate{$at}{mediawiki}{redir};
+ }
+ } else {
+ # it's an external link
+ $value = encode_entities($value);
+ }
+
+ my $redir="<meta http-equiv=\"refresh\" content=\"0; URL=$value\" />";
+ $redir=scrub($redir) if !$safe;
+ push @{$metaheaders{$page}}, $redir;
+
+ return "Redirecting to $value ...";
+ }
+
+
+ # Feed this routine a string containing <nowiki>...</nowiki> sections,
+ # this routine calls your callback for every section not within nowikis,
+ # collecting its return values and returning the rewritten string.
+ sub skip_nowiki
+ {
+ my $content = shift;
+ my $proc = shift;
+
+ my $result = "";
+ my $state = 0;
+
+ for(split(/(<nowiki[^>]*>.*?<\/nowiki\s*>)/s, $content)) {
+ $result .= ($state ? $_ : &$proc($_));
+ $state = !$state;
+ }
+
+ return $result;
+ }
+
+
+ # Converts all links in the page, wiki and otherwise.
+ sub linkify (@)
+ {
+ my %params=@_;
+
+ my $page=$params{page};
+ my $destpage=$params{destpage};
+ my $content=$params{content};
+
+ my $file=$pagesources{$page};
+ my $type=pagetype($file);
+ my $counter = 1;
+
+ if($type ne 'mediawiki') {
+ return IkiWiki::Plugin::link::linkify(@_);
+ }
+
+ my $redir = check_redirect(%params);
+ return $redir if defined $redir;
+
+ # this code was copied from MediawikiFormat.pm.
+ # Heavily changed because MF.pm screws up escaping when it does
+ # this awful hack: $uricCheat =~ tr/://d;
+ my $schemas = [qw(http https ftp mailto gopher)];
+ my $re = join "|", map {qr/\Q$_\E/} @$schemas;
+ my $schemes = qr/(?:$re)/;
+ # And this is copied from URI:
+ my $reserved = q(;/?@&=+$,); # NOTE: no colon or [] !
+ my $uric = quotemeta($reserved) . $URI::unreserved . "%#";
+
+ my $result = skip_nowiki($content, sub {
+ $_ = shift;
+
+ # Escape any anchors
+ #s/<(a[\s>\/])/<$1/ig;
+ # Disabled because this appears to screw up the aggregate plugin.
+ # I guess we'll rely on Iki to post-sanitize this sort of stuff.
+
+ # Replace external links, http://blah or [http://blah]
+ s{\b($schemes:[$uric][:$uric]+)|\[($schemes:[$uric][:$uric]+)([^\]]*?)\]}{
+ generate_external_link($1||$2, $3, \$counter)
+ }eg;
+
+ # Handle links that only contain fragments.
+ s{ \[\[ \s* (\#[^|\]'"<>&;]+) (?:\| ([^\]'"<>&;]*))? \]\] }{
+ generate_fragment_link($1, $2)
+ }xeg;
+
+ # Match all internal links
+ s{$link_regexp}{
+ generate_internal_link($page, $1, $2, $3, $4, sub {
+ my($linkpage, $linktext, $anchor) = @_;
+ return htmllink($page, $destpage, $linkpage,
+ linktext => $linktext,
+ anchor => underscorize(scrunch($anchor)));
+ });
+ }eg;
+
+ return $_;
+ });
+
+ return $result;
+ }
+
+
+ # Find all WikiLinks in the page.
+ sub scan (@)
+ {
+ my %params = @_;
+ my $page=$params{page};
+ my $content=$params{content};
+
+ my $file=$pagesources{$page};
+ my $type=pagetype($file);
+
+ if($type ne 'mediawiki') {
+ return IkiWiki::Plugin::link::scan(@_);
+ }
+
+ skip_nowiki($content, sub {
+ $_ = shift;
+ while(/$link_regexp/g) {
+ generate_internal_link($page, $1, '', '', '', sub {
+ my($linkpage, $linktext, $anchor) = @_;
+ push @{$links{$page}}, $linkpage;
+ return undef;
+ });
+ }
+ return '';
+ });
+ }
+
+
+ # Convert the page to HTML.
+ sub htmlize (@)
+ {
+ my %params=@_;
+ my $page = $params{page};
+ my $content = $params{content};
+
+
+ return $content if $markup_disabled;
+
+ # Do a little preprocessing to babysit Text::MediawikiFormat
+ # If a line begins with tabs, T:MwF won't convert it into preformatted blocks.
+ $content =~ s/^\t/ /mg;
+
+ my $ret = Text::MediawikiFormat::format($content, {
+
+ allowed_tags => [#HTML
+ # MediawikiFormat default
+ qw(b big blockquote br caption center cite code dd
+ div dl dt em font h1 h2 h3 h4 h5 h6 hr i li ol p
+ pre rb rp rt ruby s samp small strike strong sub
+ sup table td th tr tt u ul var),
+ # Mediawiki Specific
+ qw(nowiki),
+ # Our additions
+ qw(del ins), # These should have been added all along.
+ qw(span), # Mediawiki allows span but that's rather scary...?
+ qw(a), # this is unfortunate; should handle links after rendering the page.
+ ],
+
+ allowed_attrs => [
+ qw(title align lang dir width height bgcolor),
+ qw(clear), # BR
+ qw(noshade), # HR
+ qw(cite), # BLOCKQUOTE, Q
+ qw(size face color), # FONT
+ # For various lists, mostly deprecated but safe
+ qw(type start value compact),
+ # Tables
+ qw(summary width border frame rules cellspacing
+ cellpadding valign char charoff colgroup col
+ span abbr axis headers scope rowspan colspan),
+ qw(id class name style), # For CSS
+ # Our additions
+ qw(href),
+ ],
+
+ }, {
+ extended => 0,
+ absolute_links => 0,
+ implicit_links => 0
+ });
+
+ return $ret;
+ }
+
+
+ # This is only needed to support the check_redirect call.
+ sub pagetemplate (@)
+ {
+ my %params = @_;
+ my $page = $params{page};
+ my $destpage = $params{destpage};
+ my $template = $params{template};
+
+ # handle metaheaders for redirects
+ if (exists $metaheaders{$page} && $template->query(name => "meta")) {
+ # avoid duplicate meta lines
+ my %seen;
+ $template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$metaheaders{$page}}));
+ }
+
+ $template->param(tags => [
+ map {
+ link => htmllink($page, $destpage, tagpage($_), rel => "tag")
+ }, sort keys %{$tags{$page}}
+ ]) if exists $tags{$page} && %{$tags{$page}} && $template->query(name => "tags");
+
+ # It's an rss/atom template. Add any categories.
+ if ($template->query(name => "categories")) {
+ if (exists $tags{$page} && %{$tags{$page}}) {
+ $template->param(categories => [map { category => $_ },
+ sort keys %{$tags{$page}}]);
+ }
+ }
+ }
+
+ 1
committing the changes back to the origin git repository, and updating the
origin mirror. Assuming you can push to that git repository. If you can't,
and you want a mirror, and not a branch, you should disable web edits on
-your mirror.
+your mirror. (You could also point the cgiurl for your mirror at the origin
+wiki.)
## branching a wiki
--- /dev/null
+Would it work if the mirrored wiki was configured with cgiurl set to the cgiurl of the origin wiki - so that users were seamlessly redirected to the origin for edits? --[[Jamie]]
+
+> Yes, if the origin wiki is set up to ping the mirrored wiki when
+> updated, the mirror is free to use its cgi setup. (Note that the cgi will
+> leave the user on a page on the origin wiki when they save the edit.)
+> I've put a mention of this option in the page.
+> --[[Joey]]
--- /dev/null
+It's common to name the [[cgi]] "ikiwiki.cgi", and put it somewhere
+like `~/public_html/ikiwiki.cgi`, or `/var/www/wiki/ikiwiki.cgi`.
+
+If you do that, you may find that when trying to edit a page in your wiki,
+you see the raw contents of the ikiwiki.cgi program. Or get a permission
+denied problem.
+
+This is because web servers are generally not configured to run cgi scripts
+unless they're in `/usr/lib/cgi-bin/`. While you can put ikiwiki.cgi in
+there if you like, it's better to configure your web server to
+run `.cgi` programs from anywhere.
+
+These instructions are for Debian systems, but the basic
+configuration changes should work anywhere.
+
+## apache 2
+
+* Edit /etc/apache2/apache2.conf and add a line like this:
+
+ AddHandler cgi-script .cgi
+
+* Find the "Options" line for the directory where you've put the
+ ikiwiki.cgi, and add "ExecCGI" to the list of options. For example, if
+ ikiwiki.cgi is in /var/www/, edit `/etc/apache2/sites-enabled/000-default`
+ and add it to the "Options" line in the "Directory /var/www/" stanza.
+ Or, if you've put it in a `~/public_html`, edit
+ `/etc/apache2/mods-available/userdir.conf`.
+
+* You may also want to enable the [[plugins/404]] plugin.
+ To make apache use it, the apache config file will need a further
+ modification to make it use ikiwiki's CGI as the apache 404 handler.
+ Something like this, with the path adjusted to where you've put the CGI:
+
+ ErrorDocument 404 /cgi-bin/ikiwiki.cgi
+
+## lighttpd
+
+Here is how to enable cgi on [lighttpd](http://www.lighttpd.net/) and
+configure it in order to execute ikiwiki.cgi wherever it is located.
+
+* Activate cgi by linking `/etc/lighttpd/conf-available/10-cgi.conf` into `/etc/lighttpd/conf-enabled` ([doc](http://trac.lighttpd.net/trac/wiki/Docs%3AModCGI)).
+
+* Create `/etc/lighttpd/conf-available/90-ikiwiki-cgi.conf` and add a line like this:
+
+ cgi.assign = ( "ikiwiki.cgi" => "", )
+
+* Activate ikiwiki-cgi by linking `/etc/lighttpd/conf-available/90-ikiwiki-cgi.conf` into `/etc/lighttpd/conf-enabled`.
+
+* Restart lighttpd server with something like `/etc/init.d/lighttpd restart`.
+
+Note that the first part enables cgi server wide but depending on default
+configuration, it may be not enough. The second part creates a specific
+rule that allow `ikiwiki.cgi` to be executed.
+
+**Warning:** I only use this lighttpd configuration on my development
+server (offline). I am not sure of how secure this approach is.
+If you have any thought about it, feel free to let me know.
+
+## nginx
+
+* To run CGI under nginx, just use a FastCGI wrapper like [this one](http://technotes.1000lines.net/?p=23). The wrapper must be started somehow just like any other FastCGI program. I use launchd on OSX.
+
+## boa
+
+Edit /etc/boa/boa.conf and make sure the following line is not commented:
+
+ AddType application/x-httpd-cgi cgi
--- /dev/null
+## warning: lighttpd only or both?
+
+Is your warning at the bottom (you don't know how secure it is) only about
+lighttpd or it's about apache2 configuration as well?
+
+> The latter. (Although I don't know why using lighttpd would lead
+> to any additional security exposure anyway.) --[[Joey]]
+
+I'm asking this because right now I want to setup an httpd solely for the
+public use of ikiwiki on a general purpose computer (there are other things
+there), and so I need to choose the more secure solution. --Ivan Z.
+
+> AFAIU, my main simplest security measure should be running the public
+> ikiwiki's cgi under a special user, but then: how do I push to the repo
+> owned by that other user? I see, probably I should setup the public wiki
+> under the special user (so that it was able to create the cgi-script with
+> the desired permission), and then give my personal user the required
+> permissions to make a git-push by, say, creating a special Unix group for
+> this.
+
+> Shouldn't there be a page here which would document a secure public and
+> multi-user installation of ikiwiki (by "multi-user" I mean writable by a
+> group of local Unix users)? If there isn't such yet, I started writing it
+> with this discussion.--Ivan Z.
+
+> I see, perhaps a simpler setup would not make use of a Unix group, but
+> simply allow pushing to the public wiki (kept under a special user) through
+> git+ssh. --Ivan Z.
+
+>> Yes, it's certianly possible to configure git (and svn, etc) repositories so that
+>> two users can both push to them. There should be plenty of docs out there
+>> about doing that.
+>>
+>> The easiest way though is probably
+>> to add your ssh key to the special user's `.ssh/authorized_keys`
+>> and push that way. --[[Joey]]
--- /dev/null
+A [markdown mode](http://jblevins.org/projects/markdown-mode/) for
+emacs can help in editing of ikiwiki
+[[ikiwiki/markdown]] files.
--- /dev/null
+Content from sites such as YouTube can be embedded into a web page. Maybe
+you want to do this. But you'll find that the [[plugins/htmlscrubber]]
+doesn't let you. It blocks the tags used to embed such content, because
+they can be abused in many evil ways.
+
+Some plugins have been written to try to work around this problem, by
+whitelisting the html needed to embed things from a few sites like Google
+maps, calendar, videos, and YouTube. The problem with these plugins is that
+they have to be kept up to date to add new sites, and follow changes to the
+html such sites use for embedding.
+
+(Digression: The real problem with the plugins is that they hide the
+underlying trust relationship. If you decide to embed html from a site,
+you'd better trust that site. And if ikiwiki lets you enter such html, it
+needs to trust you.)
+
+The [[plugins/htmlscrubber]] offers a different way around this problem.
+You can configure it to skip scrubbing certain pages, so that content from
+elsewhere can be embedded on those pages. Then use [[plugins/lockedit]]
+to limit who can edit those unscrubbed pages.
+
+For example, suppose your blog is all under `blog/*`, and you want
+only yourself to be able to post there, and you'd like to be able to embed
+youtube videos etc in your blog. Other users can edit some pages in the
+wiki (Discussion pages, say), but not your blog posts. Then you could configure
+ikiwiki as follows:
+
+ htmlscrubber_skip => 'blog/* and !*/Discussion',
+ locked_pages => '!*/Discussion',
+
+More simply, you might want to allow yourself to embed content anywhere
+on the wiki, but scrub content written on Discussion pages:
+
+ htmlscrubber_skip => '!*/Discussion',
+ locked_pages => '!*/Discussion',
--- /dev/null
+Here's how to set up a static wiki or blog using ikiwiki with no hosting
+fees. Everything is hosted on github, both the git repository and the web
+site. Your laptop is used to generate and publish changes to it.
+
+This is possible because github now supports
+[github pages](http://github.com/blog/272-github-pages).
+
+Note that github limits free accounts to 100 mb of git storage. It's
+unlikely that a small wiki or blog will outgrow this, but we are keeping
+two copies of the website in git (source and the compiled site), and all
+historical versions too. So it could happen. If it does, you can pay github
+for more space, or you can migrate your site elsewhere.
+
+## Github Setup
+
+* Go to [github](http://github.com/) and sign up for an account, if you haven't already.
+* Be sure to add your laptop's ssh key to it so you can push to github.
+* Create a repository on github named `$YOU.github.com`, substituting your
+ *username*. This repository will be used to publish your compiled website.
+* Create a repository on github named `$YOU` (or anything else you like).
+ This repository will be used to publish the source of your website.
+ This is actually optional.
+
+## Local Setup
+
+* On your laptop, create two empty git repositories to correspond to the github repositories: <br />
+ `YOU = your github username here` <br />
+ `mkdir ~/$YOU.github.com` <br />
+ `cd ~/$YOU.github.com` <br />
+ `git init` <br />
+ `git remote add origin git@github.com:$YOU/$YOU.github.com.git` <br />
+ `mkdir ~/$YOU` <br />
+ `cd ~/$YOU` <br />
+ `git init` <br />
+ `git remote add origin git@github.com:$YOU/$YOU.git` <br />
+* Add some wiki pages, such as an `index.mdwn`, to `~/$YOU`, and check them
+ in and commit them to git. You need something to push to github. Run
+ `git push origin master` to push the source pages to github.
+
+## Publishing to Github
+
+* Now build your wiki with a command such as: <br />
+ `ikiwiki ~/$YOU ~/$YOU.github.com --refresh`
+* Each time you build the wiki you will need to commit the changes
+ to git, and push the compiled pages to github: <br />
+ `cd ~/YOU.github.com` <br />
+ `git add .` <br />
+ `git commit -a -m update` <br />
+ `git push origin master` <br />
+
+Your wiki will show up at `http://$YOU.github.com/` within ten
+minutes after the first push, and changes you push to it from then on
+should show up immediately.
+
+## Enhancements
+
+You can follow the instructions in [[laptop_wiki_with_git]] to set up an
+editable version of your wiki on your laptop. Then you can use the web
+interface for editing. You'll still need to follow the instructions above
+to publish your changes to github.
+
+It would also be possible to teach ikiwiki to push compiled pages to github
+itself via a plugin, as was done with the [[plugins/amazon_s3]] plugin. Not
+done yet!
-If you have a [[ikiwiki/blog]] that is aggregated, either on a site like Planet
+If you have a [[blog]] that is aggregated, either on a site like Planet
Debian, or just through user subscriptions, one common problem is that
-changes to the guids of items in the blog can "flood" the aggregator,
+changes to the guids of items in the blog can “flood” the aggregator,
causing all recent blog entries to be posted to the top of it.
This can happen in a lot of situations:
-* Perhaps you've just switched to ikiwiki from some other blog engine and
+* Perhaps you’ve just switched to ikiwiki from some other blog engine and
imported your data.
-* Perhaps you've turned on the `usedirs` setting, which changes all the
+* Perhaps you’ve turned on the `usedirs` setting, which changes all the
urls in your wiki. Even if you set up
[[redirections|redirections_for_usedirs]] for the old urls, you still face
the issue of flooding aggregators.
-* Perhaps you've just moved stuff around in your wiki.
+* Perhaps you’ve just moved stuff around in your wiki.
-To avoid annoying readers in these situations, it's a good idea to remove
-any existing items from your blog's news feed. That way only new items will
+To avoid annoying readers in these situations, it’s a good idea to remove
+any existing items from your blog’s news feed. That way only new items will
show up in the aggregator. The best way to do this is to add a `feedpages`
parameter to the `inline` directive for your blog, with a condition such as:
feedpages=created_after(blog/posts/old_post)
-Where "old_post" is the name of the last post you made to the blog before
-making the change. This will limit the feed to only newer posts, while stil
+Where “old_post” is the name of the last post you made to the blog before
+making the change. This will limit the feed to only newer posts, while still
displaying the old posts in the blog page.
+
+Alternatively, you can add the [[plugins/meta]] guid directives to pages,
+to force the old url to be used.
--- /dev/null
+[Here](http://blog.spang.cc/posts/migrating_from_typo_to_ikiwiki/) is a blog post that gives instructions and a script for importing posts from [Typo](http://typosphere.org/), a Ruby-on-Rails based blogging engine.
--- /dev/null
+[[!meta title="ikiwiki-wordpress-import"]]
+
+I modified the script a bit so categories and tags would actually show up in the output file.
+
+-----
+<pre>
+#!/usr/bin/env python
+
+"""
+ Purpose:
+ Wordpress-to-Ikiwiki import tool
+
+ Copyright:
+ Copyright (C) 2007 Chris Lamb <chris@chris-lamb.co.uk>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Usage: run --help as an argument with this script.
+
+ Notes:
+ I added some extra bits to include the \[[!tag foo]] stuff in the post,
+ as it wasn't before, at all. I'll diff the versions out so you can see
+ the mess I made :).
+
+"""
+
+import os, sys
+import time
+import re
+
+from BeautifulSoup import BeautifulSoup
+
+import codecs, htmlentitydefs
+
+codecs.register_error('html_replace', lambda x: (''.join([u'&%s;' \
+ % htmlentitydefs.codepoint2name[ord(c)] for c in x.object[x.start:x.end]]), x.end))
+
+def main(name, email, subdir, branch='master'):
+ soup = BeautifulSoup(sys.stdin.read())
+
+ # Regular expression to match stub in URL.
+ stub_pattern = re.compile(r'.*\/(.+)\/$')
+
+ for x in soup.findAll('item'):
+ # Ignore draft posts
+ if x.find('wp:status').string != 'publish': continue
+
+ match = stub_pattern.match(x.guid.string)
+ if match:
+ stub = match.groups()[0]
+ else:
+ # Fall back to our own stubs
+ stub = re.sub(r'[^a-zA-Z0-9_]', '-', x.title.string).lower()
+
+ commit_msg = """Importing WordPress post "%s" [%s]""" % (x.title.string, x.guid.string)
+ timestamp = time.mktime(time.strptime(x.find('wp:post_date_gmt').string, "%Y-%m-%d %H:%M:%S"))
+
+ content = '\[[!meta title="%s"]]\n\n' % (x.title.string.replace('"', r'\"'))
+ content += x.find('content:encoded').string.replace('\r\n', '\n')
+
+ # categories = x.findAll('category')
+ # categories = x.findAll({'category':True}, attrs={'domain':re.compile(('category|tag'))})
+ # categories = x.findAll({'category':True}, domain=["category", "tag"])
+ # categories = x.findAll({'category':True}, nicename=True)
+ """
+ We do it differently here because we have duplicates otherwise.
+ Take a look:
+ <category><![CDATA[Health]]></category>
+ <category domain="category" nicename="health"><![CDATA[Health]]></category>
+
+ If we do the what original did, we end up with all tags and cats doubled.
+ Therefore we only pick out nicename="foo". Our 'True' below is our 'foo'.
+ I'd much rather have the value of 'nicename', and tried, but my
+ python skillz are extremely limited....
+ """
+ categories = x.findAll('category', nicename=True)
+ if categories:
+ content += "\n"
+ for cat in categories:
+ # remove 'tags/' because we have a 'tagbase' set.
+ # your choice: 'tag', or 'taglink'
+ # content += "\n\[[!tag %s]]" % (cat.string.replace(' ', '-'))
+ content += "\n\[[!taglink %s]]" % (cat.string.replace(' ', '-'))
+ # print >>sys.stderr, cat.string.replace(' ', '-')
+
+ # moved this thing down
+ data = content.encode('ascii', 'html_replace')
+ print "commit refs/heads/%s" % branch
+ print "committer %s <%s> %d +0000" % (name, email, timestamp)
+ print "data %d" % len(commit_msg)
+ print commit_msg
+ print "M 644 inline %s" % os.path.join(subdir, "%s.mdwn" % stub)
+ print "data %d" % len(data)
+ print data
+
+if __name__ == "__main__":
+ if len(sys.argv) not in (4, 5):
+ print >>sys.stderr, "%s: usage: %s name email subdir [branch] < wordpress-export.xml | git-fast-import " % (sys.argv[0], sys.argv[0])
+ else:
+ main(*sys.argv[1:])
+
+</pre>
+-----
+
+I have another version of the script, which uses the `timestamp` from the script, and inserts that as a \[[!meta date="foodate"]]. I'm posting it here just in case I happen to be doing something to the httpd.
+
+(Hopefully I've escaped everything properly; if I missed something, check the source.)
+
+-----
+<pre>
+#!/usr/bin/env python
+
+"""
+ Purpose:
+ Wordpress-to-Ikiwiki import tool
+
+ Copyright:
+ Copyright (C) 2007 Chris Lamb <chris@chris-lamb.co.uk>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Usage: run --help as an argument with this script.
+
+ Notes:
+ I added some extra bits to include the \[[!tag foo]] stuff in the post,
+ as it wasn't before, at all. I'll diff the versions out so you can see
+ the mess I made :).
+
+"""
+
+import os, sys
+import time
+import re
+
+from datetime import datetime
+from BeautifulSoup import BeautifulSoup
+
+import codecs, htmlentitydefs
+
+codecs.register_error('html_replace', lambda x: (''.join([u'&%s;' \
+ % htmlentitydefs.codepoint2name[ord(c)] for c in x.object[x.start:x.end]]), x.end))
+
+def main(name, email, subdir, branch='master'):
+ soup = BeautifulSoup(sys.stdin.read())
+
+ # Regular expression to match stub in URL.
+ stub_pattern = re.compile(r'.*\/(.+)\/$')
+
+ for x in soup.findAll('item'):
+ # Ignore draft posts
+ if x.find('wp:status').string != 'publish': continue
+
+ match = stub_pattern.match(x.guid.string)
+ if match:
+ stub = match.groups()[0]
+ else:
+ # Fall back to our own stubs
+ stub = re.sub(r'[^a-zA-Z0-9_]', '-', x.title.string).lower()
+
+ commit_msg = """Importing WordPress post "%s" [%s]""" % (x.title.string, x.guid.string)
+ timestamp = time.mktime(time.strptime(x.find('wp:post_date_gmt').string, "%Y-%m-%d %H:%M:%S"))
+ content = '\[[!meta title="%s"]]\n' % (x.title.string.replace('"', r'\"'))
+ content += "\[[!meta date=\"%s\"]]\n" % datetime.fromtimestamp(timestamp)
+ content += x.find('content:encoded').string.replace('\r\n', '\n')
+
+ """
+ We do it differently here because we have duplicates otherwise.
+ Take a look:
+ <category><![CDATA[Health]]></category>
+ <category domain="category" nicename="health"><![CDATA[Health]]></category>
+
+ If we do the what original did, we end up with all tags and cats doubled.
+ Therefore we only pick out nicename="foo". Our 'True' below is our 'foo'.
+ I'd much rather have the value of 'nicename', and tried, but my
+ python skillz are extremely limited....
+ """
+ categories = x.findAll('category', nicename=True)
+ if categories:
+ content += "\n"
+ for cat in categories:
+ # remove 'tags/' because we have a 'tagbase' set.
+ # your choice: 'tag', or 'taglink'
+ # content += "\n\[[!tag %s]]" % (cat.string.replace(' ', '-'))
+ content += "\n\[[!taglink %s]]" % (cat.string.replace(' ', '-'))
+ # this is just debugging, and for fun
+ # print >>sys.stderr, cat.string.replace(' ', '-')
+
+ # moved this thing down
+ data = content.encode('ascii', 'html_replace')
+ print "commit refs/heads/%s" % branch
+ print "committer %s <%s> %d +0000" % (name, email, timestamp)
+ print "data %d" % len(commit_msg)
+ print commit_msg
+ print "M 644 inline %s" % os.path.join(subdir, "%s.mdwn" % stub)
+ print "data %d" % len(data)
+ print data
+
+if __name__ == "__main__":
+ if len(sys.argv) not in (4, 5):
+ print >>sys.stderr, "%s: usage: %s name email subdir [branch] < wordpress-export.xml | git-fast-import " % (sys.argv[0], sys.argv[0])
+ else:
+ main(*sys.argv[1:])
+
+</pre>
+-----
+
+
+[[!tag wordpress]]
+[[!tag python]]
+[[!tag conversion]]
+[[!tag ikiwiki]]
-[[meta title="inside .ikiwiki"]]
+[[!meta title="inside .ikiwiki"]]
The `.ikiwiki` directory contains ikiwiki's internal state. Normally,
you don't need to look in it, but here's some tips for how to do so if
I've not written actual utilities to do this yet because I've only needed
to do it rarely, and the data I've wanted has been different each time.
--[[Joey]]
+
+## the session database
+
+`.ikiwiki/sessions.db` is the session database. See the [[!cpan CGI::Session]]
+documentation for more details.
+
+## lockfiles
+
+In case you're curious, here's what the various lock files do.
+
+* `.ikiwiki/lockfile` is the master ikiwiki lock file. Ikiwiki takes this
+ lock before reading/writing state.
+* `.ikiwiki/commitlock` is locked as a semophore, to disable the commit hook
+ from doing anything.
+* `.ikiwiki/cgilock` is locked by the cgi wrapper, to ensure that only
+ one ikiwiki process is run at a time to handle cgi requests.
+
+## plugin state files
+
+Some plugins create other files to store their state.
+
+* `.ikiwiki/aggregate` is a plain text database used by the aggregate plugin
+ to record feeds and known posts.
+* `.ikiwiki/xapian/` is created by the search plugin, and contains xapian-omega
+ configuration and the xapian database.
>>> --getctime does. --[[Joey]]
>> Alas, I seem to have lost the bad index file to periodic /tmp wiping; I'll send it to you if it happens again. --[[sabr]]
+
+<!-- Add by Blanko -->
+
+## Lost password for an user
+
+This morning, a person has lost its password. I was able to do something to make another password. This is the way I take :
+
+> You can certianly do that, but do note that ikiwiki will offer to mail a
+> user a password reset link if they lost their password. --[[Joey]]
+
+### Locate the user database
+
+As tips show us, the user database is in the source file, for an example :
+
+ src/.ikiwiki/userdb
+
+### See which user to modify
+
+Because I don't know the real login of the user, I have to read all the database :
+
+ perl -le 'use Storable; my $index=Storable::retrieve("userdb"); use Data::Dumper; print Dumper $index'
+
+Then I was able to find this :
+
+ 'Utilisateur' => {
+ 'email' => 'user@pl.fr',
+ 'cryptresettoken' => '$2a$10$cfVeOoVbFw9VzMlgEbPMsu34pwHIFP84mWlkrs2RCKknZYPZkPffm',
+ 'password' => '',
+ 'resettoken' => '',
+ 'cryptpassword' => '$2a$10$H8bYq.dlb68wpnfJgVZQhOdsF9JQ06cteRfhPQPB5eHKnD5Y3u7au',
+ 'regdate' => '1226574052'
+ },
+
+Let's have a look to modify lines.
+
+### Modify the line
+
+When you have found the line to modify, take the user name, and change its password to **sc** (for an example) :
+
+ perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); $userinfo->{"Utilisateur"}->{cryptpassword}=q{$2a$10$7viOHCrUkdAVL135Kr6one1mpZQ/FWYC773G1yZ0EtQciI11sSDRS}; Storable::lock_nstore($userinfo, "userdb")'
+ perl -le 'use Storable; my $userinfo=Storable::retrieve("userdb"); $userinfo->{"Utilisateur"}->{cryptresettoken}=q{}; Storable::lock_nstore($userinfo, "userdb")'
+
+Because I don't know how suppress cryptresettoken and resettoken fields, I change their content with *null*.
+
+After all these modifications, the user *Utilisateur* could connect to its account with the password **sc**, and go to Preferences, then change its password.
+
+<!-- End of Blanko's modifications -->
-[[meta title="Integrated issue tracking with Ikiwiki"]]
+[[!meta title="Integrated issue tracking with Ikiwiki"]]
-[[meta author="Joey Hess, LinuxWorld.com"]]
+[[!meta author="Joey Hess, LinuxWorld.com"]]
-[[meta copyright="""
+[[!meta copyright="""
Copyright 2007 Joey Hess <joeyh@ikiwiki.info>, LinuxWorld.com
[First published](http://www.linuxworld.com/news/2007/040607-integrated-issue-tracking-ikiwiki.html)
on [LinuxWorld.com](http://www.linuxworld.com/), a publication of Network
World Inc., 118 Turnpike Rd., Southboro, MA 01772.
"""]]
-[[meta license="[[GPL|freesoftware]]"]]
+[[!meta license="[[GPL|freesoftware]]"]]
Wikis are not just for encyclopedias and websites anymore. You can use
Ikiwiki in combination with your revision control system to handle issue
their lifecycle. A developer can take ownership of a
bug by tagging it with something like "owner/Joey".
-To tag a wiki page, edit it and add text such as "\[[tag done]]". Note that
+To tag a wiki page, edit it and add text such as "\[[!tag done]]". Note that
adding a wiki link to "\[[done]]" will have the same categorisation effect
as a tag, but the link will show up in the body of the page, which is a
nice effect if used in a sentence such as "This was \[[done]] in version
* A typical list of all open bugs, with their full text, and a form to post new
bugs.
- \[[inline pages="bugs/* and !link(done) and !*/Discussion" actions=yes postform=yes show=0]]
+ \[[!inline pages="bugs/* and !link(done) and !*/Discussion" actions=yes postform=yes show=0]]
* Index of the 30 most recently fixed bugs.
- \[[inline pages="bugs/* and link(done) and !*/Discussion" sort=mtime show=30 archive=yes]]
+ \[[!inline pages="bugs/* and link(done) and !*/Discussion" sort=mtime show=30 archive=yes]]
* Index of the 10 most recently active bugs.
- \[[inline pages="bugs/* and !link(done) and !*/Discussion" sort=mtime show=10]]
+ \[[!inline pages="bugs/* and !link(done) and !*/Discussion" sort=mtime show=10]]
* Open security issues.
- \[[inline pages="bugs/* and link(security) and !link(done) and !*/Discussion"]]
+ \[[!inline pages="bugs/* and link(security) and !link(done) and !*/Discussion"]]
* Full text of bugs assigned to Joey.
- \[[inline pages="bugs/* and link(owner/Joey) and !link(done) and !*/Discussion" show=0]]
+ \[[!inline pages="bugs/* and link(owner/Joey) and !link(done) and !*/Discussion" show=0]]
It may seem strange to consider using a wiki for issue tracking when there
are several dedicated bug tracking systems, like Bugzilla, that handle all
Next, `git clone` the source (`$REPOSITORY`, not `$SRCDIR`)
from the server to the laptop.
-Now, set up a web server on your laptop, if it doesn't already have one.
+Now, set up a [[web_server|dot_cgi]] on your laptop, if it doesn't
+already have one.
Now you need to write a setup file for ikiwiki on the laptop. Mostly this
is standard, but a few special settings are needed:
* Configure a cgi wrapper as usual, but configure the git wrapper to
- be written to the `post-commit` hook of the git clone.
+ be written to the `post-commit` hook of the git clone, rather than the
+ usual `post-update` hook.
* By default, ikiwiki pulls and pushes from `origin`. This shouldn't be
done on the laptop, because the origin may not be accessible (when the
Use standard git commands to handle pulling from and pushing to the server.
-Note: Currently, after pulling changes, you will need to manually update
-the wiki, with a command such as `ikiwiki -setup wiki.setup -refresh`. This
-is because git 1.5.4 doesn't have a hook that is run locally after pulling
-changes. Newer versions of git will have a `post-merge` hook that should
-work for this purpose.
+Note that if changes are pulled from the server, you will need to manually
+update the wiki, with a command such as `ikiwiki -setup wiki.setup -refresh`.
+If you'd like it to automatically update when changes are merged in, you
+can simply make a symlink `post-merge` hook pointing at the `post-update`
+hook ikiwiki created.
[[DavidBremner]]
* *Updated* Now that I play with this a bit, this seems not so important. Having a seperate sync operation that I run from the laptop is no big deal, and lets me update the parts of my site not yet managed by ikiwiki at the same time.
+
+* Ok, I have finally finished to set this up. I have a question for you :) Is it mandatory to have a locally running webserver on the laptop ? I mean, do I need to setup the CGI wrapper on the laptop ? Is it possible to just add/edit/delete/whatever, git commit all the stuff and git push back to the server ? Thank you. --[[xma]]
+
+> Of course you don't need a web server on the laptop. It is useful for
+> previewing pages before publishing them though. --[[Joey]]
Next create a setup file for the laptop with
gitorigin_branch=> "",
- wrapper => "/working/dir/.git/hooks/post-commit",
+ git_wrapper => "/working/dir/.git/hooks/post-commit",
At this point, assuming you followed page above, and not my hasty summary,
2. Now create a setup file for the server (I call it server.setup).
gitorigin_branch=> "origin",
- wrapper => "/repo/wiki.git/hooks/post-update.ikiwiki"
+ git_wrapper => "/repo/wiki.git/hooks/post-update.ikiwiki"
Note the non-standard and bizzare name of the hook.
--- /dev/null
+For people that were not born with GNU emacs fingers,
+there is a markdown editor (with preview and outline)
+for [eclipse](http://www.eclipse.org) available
+[here](http://www.winterwell.com/software/markdown-editor.php).
--- /dev/null
+When using [mathopd](http://www.mathopd.org) to serve ikiwiki, be careful of your Umask settings in the mathopd.conf.
+
+With `Umask 026` in mathopd.conf, editing pages resulted in the following errors and a 404 page when the wiki tried to take me to the updated page.
+
+ append_indexes: cannot open .../[destdir]/[outputfile].html
+ open: Permission denied
+
+With `Umask 022` in mathopd.conf, editing pages works.
+
+Hopefully this prevents someone else from spending ~2 hours figuring out why this wouldn't work. ;)
+
+> More generally, if your web server uses a nonstandard umask
+> or you're getting permissions related problems in the cgi log
+> when using ikiwiki, you can force ikiwiki to use a sane umask
+> via the `umask` setting in ikiwiki's own setup file. --[[Joey]]
mkdir ~/wiki
cd ~/wiki
- cp ~/ikiwiki/doc/ikiwiki.setup .
cp -r ~/ikiwiki/doc/examples/blog/* .
+ ikiwiki -dumpsetup ikiwiki.setup
nano ikiwiki.setup
# Set destdir to /home/htdocs
# Set srcdir to /home/private/wiki
- # Set url to http://yoursite.nfshost.com/ , set cgiurl likewise
- # Uncomment the `rcs => "git"` line, and the cgi and git
- # post-update wrapper blocks.
- # Set the cgi wrapper path to /home/htdocs/ikiwiki.cgi
- # Set the git wrapper path to /home/private/wiki.git/hooks/post-update
+ # Set url to http://yoursite.nfshost.com/
+ # Set cgiurl to http://yoursite.nfshost.com/ikiwiki.cgi
+ # Uncomment the `rcs => "git"` line.
+ # Set the cgi_wrapper path to /home/htdocs/ikiwiki.cgi
+ # Set the git_wrapper path to /home/private/wiki.git/hooks/post-update
# Configure the rest to your liking and save the file.
ikiwiki-makerepo git . ../wiki.git
ikiwiki -setup ikiwiki.setup
--- /dev/null
+Here are some tips for ways to style the links
+provided by the [[plugins/parentlinks]] plugin.
+
+This plugin offers a `HTML::Template` loop that iterates over all or
+a subset of a page's parents. It also provides a few bonus
+possibilities, such as styling the parent links depending on their
+place in the path.
+
+[[!toc ]]
+
+Content
+=======
+
+The plugin provides one template loop, called `PARENTLINKS`, that
+returns the list of parent pages for the current page. Every returned
+path element has the following variables set:
+
+* `URL` (string): url to the current path element
+* `PAGE` (string): title of the current path element
+* `DEPTH` (positive integer): depth of the path leading to the
+ current path element, counting from the wiki's root, which has
+ `DEPTH=0`
+* `HEIGHT` (positive integer): distance, 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.
+* `DEPTH_n` (boolean): true if, and only if, `DEPTH==n`
+* `HEIGHT_n` (boolean): true if, and only if, `HEIGHT==n`
+
+Usage
+=====
+
+The `DEPTH_n` and `HEIGHT_n` variables allow the template writer to
+skip arbitrary elements in the parents list: they are arbitrary
+page-range selectors.
+
+The `DEPTH` and `HEIGHT` variables allow the template writer to apply
+general treatment, depending on one of these variables, to *every*
+parent: they are counters.
+
+Basic usage
+-----------
+
+As in the default `page.tmpl`, one can simply display the list of
+parent pages:
+
+ <TMPL_LOOP NAME="PARENTLINKS">
+ <a href="<TMPL_VAR NAME=URL>"><TMPL_VAR NAME=PAGE></a>/
+ </TMPL_LOOP>
+ <TMPL_VAR TITLE>
+
+
+Styling parents depending on their depth
+----------------------------------------
+
+Say you want the parent links to be styled depending on their depth in
+the path going from the wiki root to the current page; just add the
+following lines in `page.tmpl`:
+
+ <TMPL_LOOP NAME="PARENTLINKS">
+ <a href="<TMPL_VAR NAME="URL">" class="depth<TMPL_VAR NAME="DEPTH">">
+ <TMPL_VAR NAME="PAGE">
+ </a> /
+ </TMPL_LOOP>
+
+Then write the appropriate CSS bits for `a.depth1`, etc.
+
+Skip some parents, style the others depending on their distance to the current page
+-----------------------------------------------------------------------------------
+
+Say you want to display all the parents links but the wiki homepage,
+styled depending on their distance to the current page; just add the
+following lines in `page.tmpl`:
+
+ <TMPL_LOOP NAME="PARENTLINKS">
+ <TMPL_IF NAME="DEPTH_0">
+ <TMPL_ELSE>
+ <a href="<TMPL_VAR NAME="URL">" class="height<TMPL_VAR NAME="HEIGHT">">
+ <TMPL_VAR NAME="PAGE">
+ </a> /
+ </TMPL_LOOP>
+
+Then write the appropriate CSS bits for `a.height1`, etc.
+
+Full-blown example
+------------------
+
+Let's have a look at a more complicated example; combining the boolean
+loop variables provided by the plugin (`IS_ROOT` and friends) and
+`HTML::Template` flow control structures, you can have custom HTML
+and/or CSS generated for some special path components; e.g.:
+
+ <!-- all parents, skipping mother and grand'ma, inside a common div+ul -->
+ <div id="oldestparents">
+ <ul>
+ <TMPL_LOOP NAME="PARENTLINKS">
+ <TMPL_IF NAME="HEIGHT_2">
+ <TMPL_ELSE>
+ <TMPL_IF NAME="HEIGHT_1">
+ <TMPL_ELSE>
+ <li><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="PAGE"></a></li>
+ </TMPL_IF>
+ </TMPL_IF>
+ </TMPL_LOOP>
+ </ul>
+ </div>
+
+ <!-- dedicated div's for mother and grand'ma -->
+ <TMPL_LOOP NAME="PARENTLINKS">
+ <TMPL_IF NAME="HEIGHT_2">
+ <div id="grandma">
+ <a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="PAGE"></a>
+ </div>
+ <TMPL_ELSE>
+ <TMPL_IF NAME="HEIGHT_1">
+ <div id="mother">
+ <a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="PAGE"></a>
+ </div>
+ </TMPL_IF>
+ </TMPL_IF>
+ </TMPL_LOOP>
+
+ <!-- eventually, the current page title -->
+ <TMPL_VAR NAME="TITLE">
+ </div>
--- /dev/null
+This tip will describe how to allow anyone on the planet to `git push`
+changes into your wiki, without needing a special account. All a user needs
+to know is:
+
+ git clone git://your.wiki/path
+ # now modify any of the files the wiki would let you modify on the web
+ git push
+
+This is a wonderful thing to set up for users, because then they can work
+on the wiki while offline, and they don't need to mess around with web
+browsers.
+
+## security
+
+But, you might be wondering, how can this possibly be secure. Won't users
+upload all sorts of garbage, change pages you don't want them to edit, and so
+on.
+
+The key to making it secure is configuring ikiwiki to run as your git
+repository's `pre-receive` hook. There it will examine every change that
+untrusted users push into the wiki, and reject pushes that contain changes
+that cannot be made using the web interface.
+
+So, unless you have the [[plugins/attachment]] plugin turned on,
+non-page files cannot be added. And if it's turned on, whatever
+`allowed_attachments` checks you have configured will also check files
+pushed into git.
+
+And, unless you have the [[plugins/remove]] plugin turned on, no
+files can be deleted.
+
+And if you have `locked_pages` configured, then it will also affect what's
+pushed into git.
+
+Untrusted committers will also not be able to upload files with strange
+modes, or push to any branch except for the configured `gitorigin_branch`,
+or manipulate tags.
+
+One thing to keep an eye on is uploading large files. It may be easier to
+do this via git push than using the web, and that could be abused.
+
+Also, no checking is done that the authors of commits are right, so people
+can make a commit that pretends to be done by someone else.
+
+## user setup
+
+Add a dedicated user who will push in untrusted commits. This user should have
+a locked password, and `git-shell` as its shell.
+
+ root@bluebird:/home/joey>adduser --shell=/usr/bin/git-shell --disabled-password anon
+ Adding user `anon' ...
+
+## ikiwiki setup
+
+You should set up ikiwiki before turning on anonymous push in git.
+
+Edit your wiki's setup file, and uncomment the lines for
+`git_test_receive_wrapper` and `untrusted_committers`.
+
+ # git pre-receive hook to generate
+ git_test_receive_wrapper => '/srv/git/ikiwiki.info/.git/hooks/pre-receive',
+ # unix users whose commits should be checked by the pre-receive hook
+ untrusted_committers => ['anon'],
+
+The `git_test_receive_wrapper` will become the git `pre-receive` hook. The
+`untrusted_committers` list is the list of unix users who will be pushing in
+untrusted changes. It should *not* include the user that ikiwiki normally runs
+as.
+
+Once you're done modifying the setup file, don't forget to run
+`ikiwiki -setup --refresh --wrappers` on it.
+
+## git setup
+
+You'll need to arrange the permissions on your bare git repository so that
+user anon can write to it. One way to do it is to create a group, and put
+both anon and your regular user in that group. Then make the bare git
+repository owned and writable by the group. See [[rcs/git]] for some more
+tips on setting up a git repository with multiple committers.
+
+Note that anon should *not* be able to write to the `srcdir`, *only* to the bare git
+repository for your wiki.
+
+If you want to allow git over `ssh`, generate a ssh key for anon, and
+publish the *private* key for other people to use. This is optional; you
+can use `git-daemon` instead and not worry about keys.
+
+Now set up `git-daemon`. It will need to run as user `anon`, and be
+configured to export your wiki's bare git repository. I set it up as
+follows in `/etc/inetd.conf`, and ran `/etc/init.d/openbsd-inetd restart`.
+
+ git stream tcp nowait anon /usr/bin/git-daemon git-daemon --inetd --export-all --interpolated-path=/srv/git/%H%D /srv/git
+
+At this point you should be able to `git clone git://your.wiki/path` from
+anywhere, and check out the source to your wiki. But you won't be able to
+push to it yet, one more change is needed to turn that on. Edit the
+`config` file of your bare git repository, and allow `git-daemon` to
+receive pushes:
+
+ [daemon]
+ receivepack = true
+
+Now pushes should be accepted, and your wiki immediatly be updated. If it
+doesn't, check your git repo's permissions, and make sure that the
+`post-update` and `pre-receive` hooks are suid so they run as the user who
+owns the `srcdir`.
+
+## infelicities
+
+If a user tries to push a changeset that ikiwiki doesn't like, it will
+abort the push before refs are updated. However, the changeset will still
+be present in your repository, wasting space. Since nothing refers to it,
+it will be expired eventually. You can speed up the expiry by running `git
+prune`.
+
+When aborting a push, ikiwiki displays an error message about why it didn't
+accept it. If using git over ssh, the user will see this error message,
+which is probably useful to them. But `git-daemon` is buggy, and hides this
+message from the user. This can make it hard for users to figure out why
+their push was rejected. (If this happens to you, look at "'git log --stat
+origin/master..`" and think about whether your changes would be accepted
+over the web interface.)
--- /dev/null
+I've just tried this (commit c1fa07a). Recent changes shows:
+
+<div id="change-c1fa07ad4f165b42c962ba2a310681107f38c4f7" class="metadata">
+<span class="desc"><br />Changed pages:</span>
+<span class="pagelinks">
+
+<a href="http://git.ikiwiki.info/?p=ikiwiki;a=blobdiff;h=8bfa3dd7601a09b11ecbd20026849a777dc4b1b9;hp=c6302616f52ec058de5a8f5956fc512149a2f1a3;hb=1ea66c3d3f0a33bc3f04d073457b525a70380c37;f=doc/users/jondowland.mdwn"><img src="/wikiicons/diff.png" alt="diff" /></a><a href="http://ikiwiki.info/ikiwiki.cgi?page=users%2Fjondowland&do=recentchanges_link">users/jondowland</a>
+
+
+</span>
+<span class="desc"><br />Changed by:</span>
+<span class="committer">
+
+<a href="http://ikiwiki.info/ikiwiki.cgi?page=users%2Fjon&do=recentchanges_link">jon</a>
+
+</span>
+<span class="desc"><br />Commit type:</span>
+<span class="committype">git</span>
+<span class="desc"><br />Date:</span>
+<span class="changedate"><span class="relativedate" title="Mon, 10 Nov 2008 18:24:22 -0500">18:24:22 11/10/08</span>
+</div>
+
+Note that the user for the commit is 'jon', and the link points at cgi to
+create users/jon. I was wondering if that is configurable for users pushing
+via git. It would be nice perhaps to specify it in some way, perhaps via a
+git-config setting (user.name?). I'm not too familiar with exactly what the
+changeset contains. -- [[users/Jon]]
+
+> All ikiwiki can do it look at who git has recorded as the author of
+> the change (and it looks at the username part of the email address).
+> You can set `user.email` in `.git/config`. --[[Joey]]
+
+> > Ah, excellent. In which case this *should* DTRT... -- [[users/Jon]]
--- /dev/null
+Version 3.0 of ikiwiki makes some significant changes, which
+you will need to deal with when upgrading from ikiwiki 2.x.
+
+[[!toc ]]
+
+## setup file format change
+
+The layout of the setup file changed in a significant way in version 2.60
+of ikiwiki. If you have not changed yours to the new format, now would be a
+good time to do so. Some new features, like the [[plugins/websetup]]
+interface, need the new format setup file.
+
+You can convert old setup files into the new format by running
+`ikiwiki-transition setupformat your.setup`
+
+## moving settings from Preferences page
+
+The admin preferences page used to have settings for allowed attachments,
+locked pages, and banned users. These three settings have moved to the
+setup file, and will no longer appear on the admin preferences page once
+your wiki is upgraded to 3.0.
+
+You can move these preferences into the setup file by running
+`ikiwiki-transition moveprefs your.setup; ikiwiki -setup your.setup -refresh -wrappers`
+
+(Make sure you have converted the setup file to the new format first.)
+
+## prefix directives
+
+In 3.0, the syntax ikiwiki uses for [[directives|ikiwiki/directive]] has
+changed, requiring that the directive start with a bang:
+
+ \[[!directive ...]]
+
+If you would like to keep the old syntax, it is still supported, add the
+following to your setup file:
+
+ prefix_directives => 0,
+
+To convert to the new syntax, make sure that your setup file does *not*
+contain the above, then run `ikiwiki-transition prefix_directives your.setup`
+
+(And then commit the changes it makes to pages in your srcdir.)
+
+## GlobLists
+
+In 3.0, the old "GlobList" syntax for [[PageSpecs|ikiwiki/PageSpec]] is no
+longer supported. A GlobList contains multiple term, but does not separate
+them with "and" or "or":
+
+ sandbox !*/Discussion
+
+To convert this to a modern PageSpec, simply add "and" or "or" as
+appropriate between terms:
+
+ sandbox and !*/Discussion
+
+GlobLists have been deprecated for more than two years. If your wiki dates
+to the ikiwiki 1.0 era, you should check it for any that might have lurked
+unnoticed in it since back then. Ikiwiki version 2.72 will print warnings
+about any GlobLists it sees.
+
+## aggregateinternal
+
+If your wiki uses the [[aggregate|plugins/aggregate]] plugin, it will start
+to aggregate feeds to special "internal" pages.
+
+If you don't want this change, you can add the following to your setup
+file:
+
+ aggregateinternal => 0,
+
+Otherwise, follow this procedure to upgrade a wiki using the aggregate plugin:
+
+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. Use [[ikiwiki-transition]] to rename all existing aggregated `.html`
+ files in the srcdir. The command to run is
+ `ikiwiki-transition aggregateinternal your.setup`,
+3. Refresh the wiki. (`ikiwiki -setup your.setup -refresh`)
+
+## embed / googlecalendar
+
+The googlecalendar plugin has been deprecated for a long time, and is
+removed in 3.0.
+
+The embed plugin is also now deprecated, though not yet removed.
+
+If you use either plugin to embed content from google, youtube, etc,
+into your wiki, you should instead configure the [[plugins/htmlscrubber]]
+to skip sanitising some pages, via the `htmlscrubber_skip` setting.
+See [[embedding_content]] for examples.
areas. This allows you to edit ikiwiki pages with a real text editor through
the ikiwiki web interface, rather than only with direct commit
access. --[[JoshTriplett]]
+
+For Firefox or Iceweasel users, the vimperator extension is also a good
+idea. You can press Ctrl-I in the insert mode of vimperator and switch to
+an external editor, e.g. Vim. --[[WeakishJiang]]
+
+Finally, with wikis configured to allow, [[untrusted_git_push]], you can
+ditch the browser altogether. --[[Joey]]
-[[ikiwiki.vim]] is a vim syntax highlighting file for ikiwiki. Installation
-instructions are at the top of the file.
+[[ikiwiki.vim]] is a vim syntax highlighting file for ikiwiki
+[[ikiwiki/markdown]] files.
+
+Installation instructions are at the top of the file.
-I'm going to look at merging this with potwiki.vim (a vim-based personal wiki) so that you can follow wiki-links and auto-create pages etc., direct from vim. (I'm writing this incase I don't get around to it) -- [[JonDowland]]
+I'm going to look at merging this with potwiki.vim (a vim-based personal wiki) so that you can follow wiki-links and auto-create pages etc., direct from vim. (I'm writing this incase I don't get around to it) -- [[users/Jon]]
+
+----
+
+Another attempt at the same thing is here:
+<http://plasticboy.com/markdown-vim-mode/>
+
+In my tests, [[ikiwiki.vim]] works better than that one, YMMV. --[[Joey]]
" Vim syntax file
" Language: Ikiwiki (links)
-" Maintainer: Recai Oktaþ (roktasATdebian.org)
+" Maintainer: Recai Oktaş (roktasATdebian.org)
" Last Change: 2007 May 29
" Instructions:
maintain. Each of my projects has a news page with an announcements feed,
and to automatically update this when I release a new version, generating
an announcement from the debian/changelog and debian/NEWS files, I use a
-[wikiannounce](http://git.kitenet.net/?p=joey/home;a=blob_plain;f=bin/wikiannounce)
+[wikiannounce](http://git.kitenet.net/?p=joey/home.git;a=blob_plain;f=bin/wikiannounce)
program. It's somewhat specific to dealing with Debian packages, and uses a
special `announcedir` target in debian/rules, but the general idea could be
useful. --[[Joey]]
post it to [[bugs]] instead. Link items to [[todo/done]] when done.
<!-- currently commented out because I lost all my mtimes :-)
-[[if test="enabled(postsparkline)"
+[[!if test="enabled(postsparkline)"
then="""
How long will it take your todo item to be fixed? Well...
-[[postsparkline pages="todo/* and !todo/done and !link(todo/done) and !todo/*/*"
+[[!postsparkline pages="todo/* and !todo/done and !link(todo/done) and !todo/*/*"
max=12 ymin=10 formula=permonth style=bar barwidth=2 barspacing=1 height=13]]
this many are being added per month
-[[postsparkline pages="todo/* and !todo and link(todo/done)"
+[[!postsparkline pages="todo/* and !todo and link(todo/done)"
max=12 ymin=10 formula=permonth time=mtime style=bar barwidth=2 barspacing=1 height=13]]
while this many are being fixed.
"""]]
-->
-[[inline pages="todo/* and !todo/done and !link(todo/done) and
+[[!inline pages="todo/* and !todo/done and !link(todo/done) and
!link(patch) and !link(wishlist) and !todo/*/*"
feedpages="created_after(todo/supporting_comments_via_disussion_pages)"
actions=yes archive=yes rootpage="todo" postformtext="Add a new todo item titled:" show=0]]
>>>> Which would rule out openid, or other fun forms of auth. And routing all access
>>>> through the CGI sort of defeats the purpose of ikiwiki. --[[Ethan]]
-Also see [[debbug 443346]].
+Also see [[!debbug 443346]].
+
+> Just a few quick thoughts about this:
+>
+>* I'm only thinking about write ACLs. As Joey noted, read ACLs need to be done in the web server.
+>* ACLs are going to be really hard for people with direct access to the revision control system.
+> Which means that we really only need to define ACLs for web access.
+>* ACLs for web access can then be defined by the web master. These might not need to be
+> defined in the wiki pages (although they could be).
+>* Given the previous two points, can't this be done with the `match_user()`
+> function defined by the [[plugins/attachment]] plugin (see the [[ikiwiki/pagespec/attachment]] pagespec info)
+> and the [[plugins/lockedit]] plugin?
+>
+> For example, add the following to your config file:
+>
+> locked_pages => '!(user(john) and */Discussion) and *',
+>
+> would lock all pages unless you're john and editing a Discussion page.
+> It's a thought anyway :-). -- [[Will]]
+
+>> Yes, writing per-user commit ACLs has become somewhat easier with recent
+>> features. Breaking `match_user` out of attachment, and making the
+>> lockedit plugin pass`user` and `ip` params when it calls `pagespec_match`
+>> would be sufficient. And [[done]], configurable via
+>> [[plugin/lockedit]]'s `locked_pages`. --[[Joey]]
I am considering giving this a try, implementing it as a module.
Here is how I see it:
for a given (user, page, operation), as in:
<pre>
- \[[acl user=joe page=*.png allow=upload]]
- \[[acl user=bob page=/blog/bob/* allow=*]]
- \[[acl user=* page=/blog/bob/* deny=*]]
- \[[acl user=http://jeremie.koenig.myopenid.com/ page=/todo/* deny=create
+ \[[!acl user=joe page=*.png allow=upload]]
+ \[[!acl user=bob page=/blog/bob/* allow=*]]
+ \[[!acl user=* page=/blog/bob/* deny=*]]
+ \[[!acl user=http://jeremie.koenig.myopenid.com/ page=/todo/* deny=create
reason="spends his time writing todo items instead of source code"]]
</pre>
Possibly could refer to other ACL pages, as in:
<pre>
- \[[acl user=* page=/subsite/* acl=/subsite/acl.mdwn]]
+ \[[!acl user=* page=/subsite/* acl=/subsite/acl.mdwn]]
</pre>
any feed.
I found that the problem only occurs in the presence of a file that
-contains \[[inline pages="*"]].
+contains \[[!inline pages="*"]].
> How is this unexpected? By inlining _every_ page in the wiki, you're
> making that page depend on every other page; any change to any page in
> N+1th page that its PageSpec matches is a no-op.
> --[[Joey]]
-[[tag done]]
+[[!tag done]]
Here's a short script for replicating the bug. Just cut and paste this
to a shell, (it will only muck in a new /tmp/ikiwiki-test directory
cd /tmp
mkdir ikiwiki-test; cd ikiwiki-test; mkdir src
- echo '\[[inline pages="blog/*"]]' > src/myblog.mdwn
+ echo '\[[!inline pages="blog/*"]]' > src/myblog.mdwn
mkdir src/blog; echo "A blog entry" > src/blog/entry.mdwn
echo 'use IkiWiki::Setup::Standard {
srcdir => "src",
echo "not a blog entry" > src/not-a-blog.mdwn
ikiwiki --setup setup
ls -l --time-style=full-iso output/myblog/index.rss
- echo '\[[inline pages="*"]]' > src/archives.mdwn
+ echo '\[[!inline pages="*"]]' > src/archives.mdwn
ikiwiki --setup setup
ls -l --time-style=full-iso output/myblog/index.rss
echo "still not blogging" >> src/not-a-blog.mdwn
done
$ ls -l --time-style=full-iso output/myblog/index.rss
-rw-r--r-- 1 cworth cworth 459 2007-06-01 06:34:36.000000000 -0700 output/myblog/index.rss
- $ echo '\[[inline pages="*"]]' > src/archives.mdwn
+ $ echo '\[[!inline pages="*"]]' > src/archives.mdwn
$ ikiwiki --setup setup
refreshing wiki..
scanning archives.mdwn
--[[JoshTriplett]]
-[[tag soc]]
+[[!tag soc]]
[[wishlist]]
%config %links %renderedfiles %pagesources %destsources);
our $VERSION = 2.00; # plugin interface version, next is ikiwiki version
our $version="2.1";my $installdir="/usr";
- @@ -70,6 +70,7 @@ sub defaultconfig () { #{{{
+ @@ -70,6 +70,7 @@ sub defaultconfig () {
plugin => [qw{mdwn inline htmlscrubber passwordauth openid signinedit
lockedit conditional}],
timeformat => '%c',
locale => undef,
sslcookie => 0,
httpauth => 0,
- @@ -447,6 +448,15 @@ sub displaytime ($) { #{{{
+ @@ -447,6 +448,15 @@ sub displaytime ($) {
$config{timeformat}, localtime($time)));
- } #}}}
+ }
- +sub displaydate ($) { #{{{
+ +sub displaydate ($) {
+ my $time=shift;
+
+ # strftime doesn't know about encodings, so make sure
+ # its output is properly treated as utf8
+ return decode_utf8(POSIX::strftime(
+ $config{dateformat}, localtime($time)));
- +} #}}}
+ +}
+
- sub beautify_url ($) { #{{{
+ sub beautify_url ($) {
my $url=shift;
diff --git a/Plugin/inline.pm b/Plugin/inline.pm
index 8f6ab51..7bd6147 100644
--- a/Plugin/inline.pm
+++ b/Plugin/inline.pm
- @@ -148,6 +148,7 @@ sub preprocess_inline (@) { #{{{
+ @@ -148,6 +148,7 @@ sub preprocess_inline (@) {
$template->param(pageurl => urlto(bestlink($params{page}, $page), $params{destpage}));
$template->param(title => pagetitle(basename($page)));
$template->param(ctime => displaytime($pagectime{$page}));
--
1.5.2.2
-[[tag patch]]
+[[!tag patch patch/core plugins/inline]]
--- /dev/null
+I've found myself wanting to know which [[plugins]] are switched on so I know which pre-processor commands I can use. The attached [[patch]] adds a new plugin that generates the list of available plugins. -- [[Will]]
+
+> Good idea, I do see a few problems:
+>
+> - preprocessor directives do not necessarily have the same name as the
+> plugin that contains them (for example, the graphviz plugin adds a graph
+> directive). Won't keys `%{IkiWiki::hooks{preprocess}}` work?
+
+>>> Er, yeah - that's a much better solution. :) -- and done
+
+> - "listplugins" is a bit misnamed since it only does preprocessor directives.
+
+>>> Yes. Initially this was going to list all enabled plugins. Then when searching
+>>> for enabled plugins I changed my mind and decided that a list of pre-processor
+>>> directives was more useful. I'll fix that too. -- changed to `listpreprocessors`
+
+> - comment was copied from version plugin and still mentions version :-)
+
+>>> :-) -- fixed
+
+> - Seems like [[ikiwiki/formatting]] could benefit from including the
+> list.. however, just a list of preprocessor directive names is not
+> the most user-friendly thing that could be put on that page. It would
+> be nice if there were also a short description and maybe an example of
+> use. Seems like the place to include that info would be in the call
+> to `hook()`.
+> (Maybe adding that is more involved than you want to go though..)
+>
+> --[[Joey]]
+
+>> Adding a whole new hook for a usage example is more effort than I
+>> wanted to go to. I was thinking of either:
+
+>>> Just to clarify, I meant adding new parameters to the same hook call
+>>> that registers the plugin. --[[Joey]]
+
+>> - Adding a configuration for a wiki directory. If a matching page is in the
+>> specified wiki directory then the plugin name gets turned into a link to that
+>> page
+>> - Adding configuration for an external URL. Each plugin name is added as
+>> a link to the plugin name appended to the URL.
+
+>>The first option is easier to navigate and wouldn't produce broken links,
+>>but requires all the plugin documentation to be local. The second option
+>>can link back to the main IkiWiki site, but if you have any non-standard
+>>plugins then you'll get broken links.
+>>
+>>Hrm. After listing all of that, maybe your idea with the hooks is the better
+>>solution. I'll think about it some more. -- [[Will]]
+
+>>> I've also run into this problem with the websetup plugin, and
+>>> considered those ideas too. I don't like the external url, because
+>>> ikiwiki.info may be out of sync with the version of ikiwiki being used.
+>>> (Or maybe it's gone! :-) The first idea is fine, except for the bloat
+>>> issue. If turning on listpreprocessors and/or websetup means adding
+>>> hundreds of pages (and of kilobytes) to your wiki, that could be an
+>>> incentive to not turn them on..
+>>>
+>>> Hmm.. maybe the thing to do is to use _internal pages for the plugins;
+>>> then the individual pages would not be rendered, and your inlines would
+>>> still work. Although I don't know how websetup would use it then, and
+>>> also they would have to be non-internal for ikiwiki's own docwiki. Hmm.
+>>> Maybe these are two different things; one is a set of pages describing
+>>> preprocessor directives, and the second a set of pages describing
+>>> plugins. They're so closely related though it seems a shame to keep
+>>> them separate..
+>>> --[[Joey]]
+
+>>> I started implementing the hook based solution, and decided I didn't like
+>>> it because there was no nice way to rebuild pages when the preprocessor
+>>> descriptions changed. So instead I assumed that the the [[plugins]] pages
+>>> would be moved into the underlay directory. This plugin then uses an
+>>> `inline` directive to include those pages. You can use the `inline`
+>>> parameter to decide if you want to include all the descriptions or
+>>> just the titles. There is also an option to auto-create default/blank
+>>> description pages if they are missing (from a template). As preprocessor
+>>> commands don't list unless they have a description page, auto-creation
+>>> is enabled by default.
+>>>
+>>> There are three new templates that are needed. These are for:
+>>>
+>>> - The auto-created description pages are generated from `preprocessor-description.tmpl`.
+>>> - When only pre-processor names are listed, the `listpreprocessors-listonly.tmpl` template is used.
+>>> - When pre-processor descriptions are included inline, the `listpreprocessors-inline.tmpl` template is used.
+>>>
+>>> -- [[Will]]
+
+>>>> Just a quick note: pages are only created for pre-processor commands
+>>>> that exist when the `refresh` hook is called. This is before the [[shortcuts]] are
+>>>> processed. However, the list of available pre-processor commands will include
+>>>> shortcuts if they have description pages (the list is generated later, after the
+>>>> shortcuts have been added). While this was unplanned, it seems a reasonable
+>>>> tradeoff between including all the large number of shortcuts and including none. -- [[Will]]
+
+>>>>>> I think that using an inline is elegant! However, I don't understand
+>>>>>> why it has to create stub description pages? I doubt that, if a
+>>>>>> directive is missing a page, the stub will be filled out in many
+>>>>>> wikis. And it adds a lot of complexity, particularly committing a
+>>>>>> bunch of generated pages to revision control when the user just
+>>>>>> wants a plugin list seems undesirable.
+>>>>>>
+>>>>>> Seems to me it could use the inline for pages that exist, and append
+>>>>>> to the bottom a generated text for anything that is currently missing.
+>>>>>> The generated text could even have a page creation link in it if
+>>>>>> you wanted.
+>>>>>> --[[Joey]]
+
+>>>>>>> I kinda agree about the page generation. I don't like mixing an
+>>>>>>> inlined and a list though. Besides which, that ends
+>>>>>>> up keeping much of complexity of the page generation because
+>>>>>>> the code still has to detect which pages are missing. I've added
+>>>>>>> a patch that uses a list of wikilinks instead. This way available
+>>>>>>> pages get linked correctly, and missing pages get normal creation
+>>>>>>> links. The old patch is still here if you decide you prefer that. -- [[Will]]
+
+>>>>>>>> Can you explain the full/early list (why track both?) and generated parameter?
+
+>>>>>>>>> If you add in all the shortcuts you get quite a long list. My original idea
+>>>>>>>>> was to just track the plugin commands. This is the early list. But then
+>>>>>>>>> I thought that it might be nice for someone looking at wiki source and
+>>>>>>>>> seeing a shortcut to know where it came from. So I decided to make
+>>>>>>>>> displaying the full list an option, with the original concept as the default.
+
+>>>>>>>>> Another option here might be to generate the full list every time, but give
+>>>>>>>>> generated pre-processor commands (e.g. shortcuts) a different css class.
+>>>>>>>>> I'm not sure that is better than what I have though.
+
+>>>>>>>>> I keep track of both in the page state because if a command moves from
+>>>>>>>>> a shortcut to the early list (or vice versa) it changes what should be
+>>>>>>>>> displayed in the default use of the plugin. I thought about tracking just what
+>>>>>>>>> was actually used on the page, but I don't know in the needsbuild hook whether the `generated`
+>>>>>>>>> parameter has been supplied (or maybe the plugin is used twice on the page -
+>>>>>>>>> once in each form). It was just easier to track both.
+
+>>>>>>>> Only code change I'd suggest is using `htmllink` rather than
+>>>>>>>> generating a wikilink.
+
+>>>>>>>>> Yeah - that would make sense. done. -- [[Will]]
+
+Patch is applied (along with some changes..). [[done]] (But, see
+[[directive_docs]].
--- /dev/null
+Camelcase currently looks for any and call camelcase words and turns them into wiki links. This patch adds a config item called <code>camelcase_ignore</code> which is an array of camelcase words to ignore.
+
+<pre>
+--- /usr/share/perl5/IkiWiki/Plugin/camelcase.pm.orig 2008-12-24 11:49:14.000000000 +1300
++++ /usr/share/perl5/IkiWiki/Plugin/camelcase.pm 2008-12-24 12:02:21.000000000 +1300
+@@ -33,7 +33,11 @@
+ my $destpage=$params{destpage};
+
+ $params{content}=~s{$link_regexp}{
+- htmllink($page, $destpage, IkiWiki::linkpage($1))
++ if (grep {/$1/} @{ $config{'camelcase_ignore'} }) {
++ $1
++ } else {
++ htmllink($page, $destpage, IkiWiki::linkpage($1))
++ }
+ }eg;
+
+ return $params{content};
+</pre>
+
+--[[puck]]
+
+[[done]]
> to get it to appear higher up is to put it first, or to use Evil absolute
> positioning. (CSS sucks.) --[[Joey]]
-[[wishlist]]
+[[!tag done wishlist]]
>> be worthwhile to consider this option again? It seems to have a companion
>> product (wmd) with formatting widgets and a live preview pane, that is
>> promised to be MIT licensed as of the next release.... --Chapman Flack
+
+>>> What sort of integration would be needed to put in WMD?
+>>> It looks like it would need to be aware of some plugin/wikiword behavior
+>>> ... perhaps taking a Wikiword and making it appear like a link in preview, but
+>>> with a different style (perhaps diff color/font). For plugin commands,
+>>> applying a 'real' preview would probably be difficult, so it'd probably
+>>> be necessary to insert some sort of placeholder, perhaps by outputting
+>>> the text in monospace form w/ a lighter font to denote that it won't
+>>> directly be shown in the page... -- [[harningt]]
+
+>>>>> We have a wmd plugin now. --[[Joey]]
-This patch adds a space before the forward-slash in the the parent links. There is already a space after the slash.
+This [[patch]] adds a space before the forward-slash in the the parent links. There is already a space after the slash.
> I intentionally put the space after the slash and not before, because I
> like how it looks that way. So I don't plan to apply this patch unless a
>>> Yes, please. This seems to be something a lot of people want to customize. (I certainly do -- a forward slash only looks natural to Unix users) --[[sabr]]
+>> Joey, would I be right to summarize your position on this as "people who
+>> want to change the text of the templates should maintain their own version
+>> of the `.tmpl` files"? It's not clear to me how this todo item could be
+>> closed in a way acceptable to you, except perhaps as WONTFIX. --[[smcv]]
+
Before:
ikiwiki/ todo/ Add space before slash in parent links
+<TMPL_VAR INDEXLINK> / <TMPL_VAR TITLE>
</span>
</div>
+
+----
+
+It's almost implicit in some of the discussion above but this can be achieved locally if you fork your templates directory from ikiwiki's, with an ammendment such as
+
+ <h1><TMPL_LOOP NAME="PARENTLINKS"><a
+ href="<TMPL_VAR NAME=URL>"><TMPL_VAR NAME=PAGE></a>
+ →
+ </TMPL_LOOP><TMPL_VAR TITLE></h1>
+
+This is what I do on my site for example. -- [[Jon]]
+
+> You don't actually need to fork the whole directory, "only" `page.tmpl` -
+> put `templatedir => "/foo/templates"` in your setup file, copy `page.tmpl`
+> to that directory, and modify it there. IkiWiki will look in `templatedir`
+> first, then fall back to its default templates if any are missing from
+> `templatedir`.
+>
+> (Admittedly, `page.tmpl` is the hardest to maintain a fork of, because it
+> tends to change whenever a new plugin is added...) --[[smcv]]
> be a good idea to check out current git master before spending time on
> patches in the future. Thanks for the work anyway.. --[[Joey]]
-[[tag done]]
+[[!tag done]]
--- IkiWiki/Plugin/mdwn.pm.orig 2008-03-08 11:33:50.000000000 +0100
+++ IkiWiki/Plugin/mdwn.pm 2008-03-08 13:37:21.000000000 +0100
- @@ -28,14 +28,20 @@ sub htmlize (@) { #{{{
+ @@ -28,14 +28,20 @@ sub htmlize (@) {
$markdown_sub=\&Markdown::Markdown;
}
else {
-- [[HenrikBrixAndersen]]
-[[tag patch]]
+[[!tag patch]]
* Possibly add [[plugins/table]].
--[[JoshTriplett]]
+
+[[done]]
--- /dev/null
+I need to display part of my pages' path in the `<title>` meta HTML
+header instead of their basename ; e.g. for /abs/path/to/basename, I'd
+like to set it to path/to/basename.
+
+Of course, one might consider it's my own problem, as I could
+workaround this in my templates, and replace, in the `<title>` meta
+HTML header, `<TMPL_VAR TITLE>` with a `TMPL_LOOP` on `PARENTLINKS`,
+but...
+
+- it's ugly (call it a semantic hijacking if you want) ; a side-effect
+ of this ugliness is :
+- it defeats any further plugin's (e.g. [[plugins/meta]])
+ attempt to override the default title with a nicer one ;
+- all parents appear : there is no way to specify how deep to go up in
+ the parents tree.
+
+So I really want to avoid this ugly workaround.
+
+Looking at `Render.pm`, the second solution I thought of was :
+
+- add a `parents_in_page_title` configuration option (default=0, i.e.
+ the current behaviour) ;
+- modify `Render.pm` to insert as much parents as possible (up to
+ `N=parents_in_page_title`), separated by '/', in the `title`
+ template parameter, before the actual page basename ; I personally
+ would use N=2.
+
+The only problems I can see with this approach are :
+
+- it requires modification of the core, which may not be desirable
+- the resulting title would be unconditionally overridden by the meta
+ plugin, and I can think of no clean solution to make this
+ configurable without hacking [[plugins/meta]], which I'd rather not
+ to ; I don't care, but once you add a ad-hoc feature to the core,
+ you can be sure someone will want a more generic version in less than
+ three months ;)
+
+I'm not too convinced writing a plugin for such a small feature isn't
+overdoing it, so I'm tempted to implement this solution in the
+simplest way : the generated title would be the default and could be
+overridden later by plugins.
+
+Joey, what do you think ?
+
+(Before starting to write any single line of code, I need to know how
+much you are on the "if you can do it as a plugin, don't ever modify
+the core" side... :)
+
+> My general philosophy is that the core should be flexible enough to allow
+> plugins to do arbitrary useful stuff. And there are some things in-core
+> that I'd like to get out (such as backlinks processing), but that cannot
+> currently be moved out efficiently. KISS is also part of my pholisophy.
+>
+> So no, I don't like adding new options to the core that few users will
+> want to use.
+
+In case you're on the hardcore side, I would probably write
+a dedicated plugin, called `genealogictitle` or whatever, and :
+
+- use the pagetemplate hook to modify the `title` template parameter,
+ and maybe set `title_overridden`, as does the meta plugin
+- add a `genealogictitle_depth` configuration option to tell how many
+ parents to display
+- maybe add a `genealogictitle_overrides_meta` or whatever to decide
+ whether a title overridden by [[plugins/meta]] should be overridden
+ by genealogictitle ; but anyway, I've not found, in the plugins
+ documentation, any hint about the order in which the plugins are
+ called for a given hook, so the "choose the strongest between meta
+ and genealogictitle" thing might just be more complicated... (no,
+ I did not Read The Nice Source, yet).
+
+-- intrigeri
+
+> Plugin sounds reasonable. --[[Joey]]
+
+>> 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|pedigree_plugin]], so
+>> I'm tagging this one wontfix^W [[done]]. I'm sorry. -- intrigeri
--- /dev/null
+The new [[plugins/rename]] plugin allows files to be renamed, but doesn't seem to allow changing the page type. It would be nice if there was a way to change page type through the web interface.
+
+#### Background
+
+I'm currently moving a couple of projects from [Trac](http://trac.edgewall.org/) to Ikiwiki. I don't want to have to re-do all the wiki formatting at once. Initially I simply imported all the old wiki pages without suffixes. This made them appear on the web as raw un-editable text. I wanted other project members to be able to do the updating to the new markup language, so I then renamed the files to use '.txt' suffixes, and that allows them to be edited. Unfortunately, there is still no way to convert them to '.mdwn' files on the web.
+
+I was hoping that the [[plugins/rename]] plugin would allow web uses to change the filename suffix, but it doesn't. This means that the page type can be set on page creation using the web interface, but cannot be changed thereafter using the web interface. I was thinking the UI would be something like adding the 'Page type' drop-down menu that appears on the creation page to either the edit or rename pages.
+
+#### [[patch]]
+
+ diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm
+ index 527ee88..123b772 100644
+ --- a/IkiWiki/Plugin/rename.pm
+ +++ b/IkiWiki/Plugin/rename.pm
+ @@ -43,7 +43,7 @@ sub check_canrename ($$$$$$$) {
+
+ # Dest checks can be omitted by passing undef.
+ if (defined $dest) {
+ - if ($src eq $dest || $srcfile eq $destfile) {
+ + if ($srcfile eq $destfile) {
+ error(gettext("no change to the file name was specified"));
+ }
+
+ @@ -54,7 +54,7 @@ sub check_canrename ($$$$$$$) {
+ }
+
+ # Must not be a known source file.
+ - if (exists $pagesources{$dest}) {
+ + if ($src ne $dest && exists $pagesources{$dest}) {
+ error(sprintf(gettext("%s already exists"),
+ htmllink("", "", $dest, noimageinline => 1)));
+ }
+ @@ -97,6 +97,24 @@ sub rename_form ($$$) {
+ $f->field(name => "do", type => "hidden", value => "rename", force => 1);
+ $f->field(name => "page", type => "hidden", value => $page, force => 1);
+ $f->field(name => "new_name", value => IkiWiki::pagetitle($page), size => 60);
+ + if (!$q->param("attachment")) {
+ + # insert the standard extensions
+ + my @page_types;
+ + if (exists $IkiWiki::hooks{htmlize}) {
+ + @page_types=grep { !/^_/ }
+ + keys %{$IkiWiki::hooks{htmlize}};
+ + }
+ +
+ + # make sure the current extension is in the list
+ + my ($ext) = $pagesources{$page}=~/\.([^.]+)$/;
+ + if (! $IkiWiki::hooks{htmlize}{$ext}) {
+ + unshift(@page_types, $ext);
+ + }
+ +
+ + $f->field(name => "type", type => 'select',
+ + options => \@page_types,
+ + value => $ext, force => 1);
+ + }
+ $f->field(name => "attachment", type => "hidden");
+
+ return $f, ["Rename", "Cancel"];
+ @@ -223,12 +241,19 @@ sub sessioncgi ($$) {
+ my $dest=IkiWiki::possibly_foolish_untaint(IkiWiki::titlepage($q->param("new_name")));
+
+ # The extension of dest is the same as src if it's
+ - # a page. If it's an extension, the extension is
+ + # a page. If it's an attachment, the extension is
+ # already included.
+ my $destfile=$dest;
+ if (! $q->param("attachment")) {
+ - my ($ext)=$srcfile=~/(\.[^.]+)$/;
+ - $destfile.=$ext;
+ + my $type=$q->param('type');
+ + if (defined $type && length $type && $IkiWiki::hooks{htmlize}{$type}) {
+ + $type=IkiWiki::possibly_foolish_untaint($type);
+ + } else {
+ + my ($ext)=$srcfile=~/\.([^.]+)$/;
+ + $type=$ext;
+ + }
+ +
+ + $destfile.=".".$type;
+ }
+
+ check_canrename($src, $srcfile, $dest, $destfile,
+
+-- [[users/Will]]
+
+Thanks, fixed a few bugs and applied. --[[Joey]]
+[[done]]
--- /dev/null
+This patch allows disabling the edit and preferences link in the config file. It is backwards compatible (so peoples edit and preferences links won't suddenly vanish).
+
+To disable edit or prefs respectively, add the following to the config file:
+
+<pre>
+ 'edit' => 0,
+ 'prefs' => 0,
+</pre>
+
+Patch:
+<pre>
+--- /usr/share/perl5/IkiWiki/Render.pm.orig 2008-12-23 16:49:00.000000000 +1300
++++ /usr/share/perl5/IkiWiki/Render.pm 2008-12-23 16:55:40.000000000 +1300
+@@ -80,8 +80,10 @@
+ my $actions=0;
+
+ if (length $config{cgiurl}) {
+- $template->param(editurl => cgiurl(do => "edit", page => $page));
+- $template->param(prefsurl => cgiurl(do => "prefs"));
++ $template->param(editurl => cgiurl(do => "edit", page => $page))
++ if ! defined $config{edit} || (defined $config{edit} && $config{edit} == 1);
++ $template->param(prefsurl => cgiurl(do => "prefs"))
++ if ! defined $config{prefs} || (defined $config{prefs} && $config{prefs} == 1);
+ $actions++;
+ }
+
+</pre>
+
+> On irc, you said, "That was to allow the hack to of using wikistatedir to
+> allow me to generate two websites, one with inline editting, the other a
+> static page for public consumption."
+>
+> The edit and preferences links can already be disabled by editing
+> `page.tmpl`. (Look for PREFSURL and EDITURL).
+>
+> More to the point though, disabling those links does not disable anyone
+> consticting the urls by hand and logging in and editing a page. So you'd
+> really want to disable the editpage plugin in the setup file for the
+> public, static wiki. Sounds like you might also want to turn off cgi
+> entirely for that build. --[[Joey]]
+
+>> I want to retain the same page.tmpl for both sites (different templates
+>> will just increase the maintenance hell), so disabling the links in the
+>> config for one public site works better in my case.
+>>
+>> I do have the editpage plugin disabled for the public static wiki, but
+>> the link still appears on the site. I want to keep the cgi on, so that
+>> the site is still searchable. --[[puck]]
+
+>>> For me, disabling the editpage plugin does make the "Edit" link
+>>> disappear (this is with 3.03) but as far as I can tell, "Preferences"
+>>> is not controlled by any plugin. It would be nice if it were; I am
+>>> trying to achieve a configuration where the only action supported
+>>> via CGI is blog-style comments. --[Zack](http://zwol.livejournal.com/)
+
+>>> Like [[puck]], I'd like to keep search available but I want to disable all
+>>> login facitilities and thus disable the "Preferences" link.
+>>>
+>>> After digging a little bit in the source code, my first attempt was to make
+>>> the "Preferences" link appear only if there is `sessioncgi` hooks
+>>> registered. But this will not work as the [[plugins/inline]] plugin also
+>>> defines it.
+>>>
+>>> Looking for `auth` hooks currently would not work as at least
+>>> [[plugins/passwordauth]] does not register one.
+>>>
+>>> Adding a new `canlogin` hook looks like overkill to me. [[Joey]], how
+>>> about making registration of the `auth` hook mandatory for all plugins
+>>> making sense of the "Preferences" link? --[[Lunar]]
+
+>>>> Hmm, using the `auth` hook existance does seem like a nice solution.
+>>>> While splitting the preferences code out into its own plugin is
+>>>> easily enough done, it has the minor problem of being yet another
+>>>> file nearly all ikiwikis will have to load, and also, prefs would
+>>>> have to be disabled manually. So I like that using the hook would
+>>>> cause it to auto-disable if nothing uses it. It's a bit ugly that
+>>>> passwordauth doesn't need an auth hook (it could be reorged to
+>>>> use it instead of formbuilder, maybe) and would probably just have an
+>>>> empty one. Thanks for the idea. --[[Joey]] [[done]]
+
+>>>>> Thanks for implementing it! --[[Lunar]]
--- /dev/null
+Below is a [[patch]] to [[plugins/edittemplate]] that does a few things:
+
+ * It defaults the type of the file to be created to the same type as the template.
+ * It adds a 'silent' parameter to the directive that stops it from printing out what what registered.
+ * It makes the description of what was registered link to the template page (which gives feedback for typos or allows template creation)
+ * It adds a colon to the standard string correcting the syntax.
+
+[[done]] except for the colon change; it's referring to the template as an
+edittemplate there. --[[Joey]]
+
+----
+
+ diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm
+ index 98308de..c381940 100644
+ --- a/IkiWiki/Plugin/edittemplate.pm
+ +++ b/IkiWiki/Plugin/edittemplate.pm
+ @@ -56,8 +56,14 @@ sub preprocess (@) {
+
+ $pagestate{$params{page}}{edittemplate}{$params{match}}=$params{template};
+
+ - return sprintf(gettext("edittemplate %s registered for %s"),
+ - $params{template}, $params{match});
+ + return "" if ($params{silent} && IkiWiki::yesno($params{silent}));
+ +
+ + my $link=IkiWiki::linkpage($params{template});
+ + add_depends($params{page}, $link);
+ + my $linkHTML = htmllink($params{page}, $params{destpage}, $link);
+ +
+ + return sprintf(gettext("edittemplate: %s registered for %s"),
+ + $linkHTML, $params{match});
+ }
+
+ sub formbuilder (@) {
+ @@ -89,6 +95,9 @@ sub formbuilder (@) {
+ if (pagespec_match($p, $pagespec, location => $registering_page)) {
+ $form->field(name => "editcontent",
+ value => filltemplate($pagestate{$registering_page}{edittemplate}{$pagespec}, $page));
+ + $form->field(name => "type",
+ + value => pagetype($pagesources{$pagestate{$registering_page}{edittemplate}{$pagespec}}))
+ + if $pagesources{$pagestate{$registering_page}{edittemplate}{$pagespec}};
+ return;
+ }
+ }
+
--- /dev/null
+This is a [[patch]] to allow filenames that are just the type. The best example of this is wanting to
+pass a `Makefile` through one of the [[todo/syntax_highlighting/]] plugins. With this patch,
+if the plugin can process files of type `.Makefile` then it will also process `Makefile`.
+
+I put this patch on the [[todo/syntax_highlighting/]] page a while ago, but it seemed to get
+lost because it didn't have its own bug to track it. Now it does :). -- [[Will]]
+
+> This changes `pagename()`, but what about `pagetype()`?
+> Many things in ikiwiki check if `pagetype($file)` returns
+> true to see if it's a page, etc. --[[Joey]]
+
+>> I think this patch is complete. It does not change `pagename()`, it
+>> changes `pagetype()` (the diff is fairly old - line numbers may have
+>> changed).
+>>
+>> Before this patch, `pagetype()` required a `.` in the page name. With
+>> this patch it doesn't, as long as the extension is being kept. This allows
+>> the filename to be all extension. `pagename()` relies on `pagetype()`
+>> to detect the type. `pagename()` also removes the extension on some
+>> pages, but this patch only affects pages where the extension isn't
+>> removed.
+>>
+>> So, yeah, I think this patch is complete. :) -- [[Will]]
+
+>>> Thanks, [[applied|done]], but I added a noextension parameter,
+>>> since having keepextension allow files with no extension didn't make
+>>> sense. Also, made it work for pages in subdirs.. --[[Joey]]
+
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index 8d728c9..1bd46a9 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -618,6 +618,8 @@ sub pagetype ($) {
+
+ if ($page =~ /\.([^.]+)$/) {
+ return $1 if exists $hooks{htmlize}{$1};
+ + } elsif ($hooks{htmlize}{$page}{keepextension}) {
+ + return $page;
+ }
+ return;
+ }
-[[tag wishlist]]
-[[tag patch]]
+[[!tag wishlist]]
+[[!tag patch]]
-In our team internal wiki, we wish to impose a policy that all edits must have a comment. Patch in [[debbug 450620]].
+In our team internal wiki, we wish to impose a policy that all edits must have a comment. Patch in [[!debbug 450620]].
> Good idea! I also hate empty commit comments, but I know that it's also a matter
> of human mentality. Of course, you can forbid users to commit empty comments,
[scmbug](http://www.mkgnu.net/?q=scmbug) might help here. --[[JoshTriplett]]
-[[tag soc]]
+[[!tag soc]]
-[[tag wishlist]]
+[[!tag wishlist]]
This patch adds function bestdir() which returns best directory from the directory structure. This is in addition to the bestlink() function which is there in IkiWiki.pm
+> Um, what is this for? :-) It would probably be a lot easier to review if it
+> had documentation, and/or a plugin that used it. --[[smcv]]
+
-------
Index: IkiWiki.pm
+++ IkiWiki.pm (working copy)
@@ -391,6 +391,35 @@
return "";
- } #}}}
+ }
- +sub bestdir ($$) { #{{{
+ +sub bestdir ($$) {
+ my $page=shift;
+ my $link=shift;
+ my $cwd=$page;
+ }
+
+ return "";
- +} #}}}
+ +}
+
- sub isinlinableimage ($) { #{{{
+ sub isinlinableimage ($) {
my $file=shift;
----
-[[users/arpitjain]]
-[[tag patch]]
+[[!tag patch patch/core]]
--- /dev/null
+- Is there some implicit license for patches posted on the wiki?
+ I would like to maybe use this in [[todo/mbox]] --[[DavidBremner]]
+
+> If it's not clear to me that a patch is a derivative work of ikiwiki, I
+> always ask for a license clarification before adding it to ikiwiki.
+> --[[Joey]]
> I sorta take your point about bug numbers. It can be a pain to refer to
> 'using_a_wiki_for_issue_tracking' as a bug name in a place like a
> changelog.
->
+
+>> Would a modified [[plugins/inline]] plugin that allowed new pages, but without a title field, be ok?
+>> When you hit the edit button it just chooses a new number and makes a page with that
+>> name.
+
+>> The only issue I can see with this is if you're using a distributed wiki for
+>> distributed bug tracking. In that case you're going to have to make sure that you
+>> don't get conflicting bug ids.
+>> Maybe there should be two options - consecutive numbering, and uuid numbering
+>> which uses a random (128 bit, base64 encoded = 22 chars) name. -- [[Will]]
+
> OTOH, I don't see a need for specially formatted commit messages to be
> used to close bugs. Instead, if your BTS is kept in an ikiwiki wiki in
> an RCS along with your project, you can do like I do here, and just edit a
>> look like a wikipage anymore, but rather something like the Debian
>> BTS web-interface, but it would still benefit from wikilinks to the
>> documentation in the wiki etc.
->>
+
+>>> I think it is useful to look at these things separately:
+>>>
+>>> * Bug numbers: See above.
+>>> * Automatic timestamps on comments: this already exists with the inline directive.
+>>> * Email interface: You can certainly get an rss feed of what changes in the wiki.
+>>> * You didn't mention [[todo/structured_page_data]] but that is, I think, part
+>>> of what you seem to be saying.
+>>> * [[todo/tracking_bugs_with_dependencies]] is also important.
+>>>
+>>> -- [[Will]]
+
>> About the commit message interface: I was thinking about a project
>> architecture where the code is kept in a separate revision control
>> system branch than the metadata (blog, wiki, BTS). This would IMHO
--[[JasonBlevins]], March 23, 2008 21:41 EDT
-[[tag soc]] [[tag wishlist]]
+[[!tag soc]] [[!tag wishlist]]
In some situations, it makes sense to have the repository in use by ikiwiki reside on a different machine. In that case, one could juggle SSH keys for the `post-update` hook. A better way may be to provide a different `do` parameter handler for the CGI, which would pull new commits to the working clone and refresh the wiki. Then, the remote `post-update` hook could just `wget` that URL. To prevent simple DoS attacks, one might assign a simple password.
-[[tag wishlist]]
+[[!tag wishlist]]
> [[done]] via the pinger and pingee plugins --[[Joey]]
>
>> No, although the existing svn backend could fairly esily be modified into
>> a CVS backend, by someone who doesn't mind working with CVS. --[[Joey]]
+>>
+>>> Wouldn't say I don't mind, but I needed it. See [[plugins/contrib/cvs]]. --[[Schmonz]]
+
+[[!tag wishlist]]
It would be nice to specify a minimum length for the change log for web edits, and if it's only required vs. non-required. I realise this is not going to solve the problem of crap log messages, but it helps guard against accidental submissions which one would have logged. Mediawiki/wikipedia has that option, and I find it a useful reminder. --[[madduck]]
-[[tag wishlist]]
+> +1 --[[lnussel]]
+
+[[!tag wishlist]]
--- /dev/null
+The [[ikiwiki/directive/inline]] directive allows the creation of new pages.
+It would be nice if it was possible to specify default text for the new post.
+For example:
+
+ \[[!inline pages="blog/* and !*/Discussion" postform="yes" newposttemplate="blogtemplate.mdwn"]]
+
+This would allow you to create a new blog post. When you hit the `Edit` button, the system presents
+you with an edit form as normal, but rather than being empty, it has the text from `blogtemplate.mdwn`.
+
+Inline below is a [[patch]] that implements this:
+
+----
+
+ diff --git a/IkiWiki/Plugin/editpage.pm b/IkiWiki/Plugin/editpage.pm
+ index bb21ed2..10c985c 100644
+ --- a/IkiWiki/Plugin/editpage.pm
+ +++ b/IkiWiki/Plugin/editpage.pm
+ @@ -60,7 +60,7 @@ sub cgi_editpage ($$) {
+
+ decode_cgi_utf8($q);
+
+ - my @fields=qw(do rcsinfo subpage from page type editcontent comments);
+ + my @fields=qw(do rcsinfo subpage from page type editcontent comments templatepage);
+ my @buttons=("Save Page", "Preview", "Cancel");
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+ @@ -117,9 +117,20 @@ sub cgi_editpage ($$) {
+ }
+ else {
+ $type=$form->param('type');
+ +
+ + my $defaultContent = "";
+ + my $templatepage = $form->param('templatepage');
+ + if ($templatepage && $pagesources{$templatepage}) {
+ + $defaultContent = readfile(IkiWiki::srcfile($pagesources{$templatepage}));
+ + }
+ +
+ if (defined $type && length $type && $hooks{htmlize}{$type}) {
+ $type=possibly_foolish_untaint($type);
+ }
+ + elsif ($templatepage && $pagesources{$templatepage}) {
+ + # favor the type of the template page
+ + $type=pagetype($pagesources{$templatepage});
+ + }
+ elsif (defined $from && exists $pagesources{$from}) {
+ # favor the type of linking page
+ $type=pagetype($pagesources{$from});
+ @@ -129,7 +140,7 @@ sub cgi_editpage ($$) {
+ if (! $form->submitted) {
+ $form->field(name => "rcsinfo", value => "", force => 1);
+ }
+ - $form->field(name => "editcontent", validate => '/.+/');
+ + $form->field(name => "editcontent", value => $defaultContent, force => 0, validate => '/.+/');
+ }
+
+ $form->field(name => "do", type => 'hidden');
+ diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm
+ index 8efef3f..075d7d8 100644
+ --- a/IkiWiki/Plugin/inline.pm
+ +++ b/IkiWiki/Plugin/inline.pm
+ @@ -271,6 +271,7 @@ sub preprocess_inline (@) {
+ $rootpage=$params{page};
+ }
+ $formtemplate->param(rootpage => $rootpage);
+ + $formtemplate->param(templatepage => $params{newposttemplate}) if $params{newposttemplate};
+ $formtemplate->param(rssurl => $rssurl) if $feeds && $rss;
+ $formtemplate->param(atomurl => $atomurl) if $feeds && $atom;
+ if (exists $params{postformtext}) {
+ diff --git a/templates/blogpost.tmpl b/templates/blogpost.tmpl
+ index 7eeede6..5c8b34c 100644
+ --- a/templates/blogpost.tmpl
+ +++ b/templates/blogpost.tmpl
+ @@ -8,6 +8,9 @@
+ </TMPL_IF>
+ <input type="hidden" name="do" value="blog" />
+ <input type="hidden" name="from" value="<TMPL_VAR ROOTPAGE>" />
+ +<TMPL_IF NAME="TEMPLATEPAGE">
+ +<input type="hidden" name="templatepage" value="<TMPL_VAR TEMPLATEPAGE>" />
+ +</TMPL_IF>
+ <input type="hidden" name="subpage" value="1" />
+ <TMPL_VAR POSTFORMTEXT>
+ <input name="title" size="40" />
+
+---
+
+Perhaps I'm misunderstanding something, but can't you use already existing
+in-house means instead of this patch; use a procedure as I do in the Hurd wiki?
+<http://www.bddebian.com/~wiki/config_edittemplate/> with one template:
+<http://www.bddebian.com/~wiki/config_edittemplate/regular_page/>.
+-- [[tschwinge]]
+
+> You are entirely correct. I thought I'd seen it somewhere, but then couldn't
+> find it when I came to use it. If the patch isn't applied (and I can see arguments
+> on both sides of that debate), then at least a pointer to
+> [[ikiwiki/directive/edittemplate]] should be added to [[ikiwiki/directive/inline]]
+> (and I'd make that change myself, but the edit needs to happen in the underlay,
+> not in the online docs). -- [[Will]]
+
+>> Go ahead and make the edit, ikiwiki's source is arranged such that edits
+>> on this wiki to files that form the underlay will affect the underlay.
+>> (Clearly I won't be adding duplicate functionality.)
+>> --[[Joey]]
+
+>>> Edit made. [[done]] -- [[Will]]
-[[tag wishlist]]
+[[!tag wishlist]]
A useful item, I think, would be for an option to disable certain pages from being indexed.
--- /dev/null
+It would be nice to have feature parity with [Trac](http://trac.edgewall.org/). Note that it is expected that the
+implementation will be quite different, but IkiWiki should support the same uses.
+
+Features needed:
+
+ * Wiki, duh.
+ * Source code viewing: This can be handled quite well with a [[shortcut|shortcuts]] to an external source viewer, or by putting
+ the source in the wiki itself (see the [[todo/automatic_use_of_syntax_plugin_on_source_code_files]] wishlist item and [[todo/syntax_highlighting]] todo item).
+ * This could be improved with [[todo/source_link]].
+ * Currently the source highlighting is a little problematic, as there can be two source files with the same wikiname.
+ e.g. a `hello-world.c` and `hello-world.h`. See [[bugs/multiple_pages_with_same_name]]
+ > That bug was fixed before you linked to the page. :-)
+ >> I was the one that fixed it... :) -- [[Will]]
+ * Trac 'Timeline' feature: view history of the RCS - the `recentchanges` button.
+ * Trac 'Roadmap' feature: Which TODOs/bugs are needed for which milestones. Use the [[plugins/progress]] directive to show percentage complete for each milestone.
+ * Bug tracking: see [[tips/integrated_issue_tracking_with_ikiwiki]] and [[todo/Updated_bug_tracking_example]].
+ * Queries on bug database: e.g. all open bugs that don't depend on an open bug. See [[todo/tracking_bugs_with_dependencies]] and [[todo/structured_page_data]].
+ * Build Status: Maybe this is just a link to an external (centralised) status board (e.g. [BuildBot](http://buildbot.net/)).
+
+-- [[Will]]
+
+[[!tag wishlist]]
+[[!template id=gitbranch branch=origin/gallery author="[[arpitjain]]"]]
+
New Version of gallery is available now. Few more features have been added like support for multiple pages, sorting and resizing of images etc.
-SVN repository of plugin is located at http://ned.snow-crash.org:8080/svn/ikiwiki-gallery
+Gallery repo is now available at <http://github.com/joeyh/ikiwiki/tree/gallery>
--[[arpitjain]]
--[[Joey]]
-[[tag soc]]
+[[!tag soc]]
-[[tag wishlist]]
+[[!tag wishlist]]
----
Plugin can be downloaded from [here](http://myweb.unomaha.edu/~ajain/gallery.tar).
It can be used as : <br>
-\[[gallery imagedir="images" thumbnailsize="200x200" cols="3" alt="Can not be displayed" title="My Pictures"]]
+\[[!gallery imagedir="images" thumbnailsize="200x200" cols="3" alt="Can not be displayed" title="My Pictures"]]
where-<br>
* imagedir => Directory containing images. It will scan all the files with jpg|png|gif extension from the directory and will put it in the gallery.<br>
Additional details are available [here](http://myweb.unomaha.edu/~ajain/ikiwikigallery.html).
-[[tag patch]]
+[[!tag patch]]
> I'd love to merge this into ikiwiki.
>
> the gallery and put it in a "gallery" branch of my git repository.
>
> --[[Joey]]
+
+----
+
+See also [[/users/smcv/gallery]] for another implementation of the same sort of
+thing. Unfortunately, none of the implementation ideas
+I have there seem quite right either... --[[smcv]]
--- /dev/null
+[[!tag wishlist patch]]
+
+# Context
+
+I may have missed a simple way to achieve what I need without
+modifying ikiwiki, so here is the context.
+
+I have a first-level directory (called `bricks`) containing a bunch of
+wiki pages :
+
+ /bricks
+ |
+ |- bla.mdwn
+ |
+ |- bli.mdwn
+ |
+ `- ...
+
+I have two groups of tags called `direction` and `usage`, stored in
+two sub-directories of `$tagbase` :
+
+ /tag
+ |
+ |- direction
+ | |- d1.mdwn
+ | |- d2.mdwn
+ | |- ...
+ |
+ |- usage
+ | |- u1.mdwn
+ | |- u2.mdwn
+ | |- ...
+
+Any page in `/brick` can be tagged with one or more tags from any of
+these tags-groups.
+
+I need to present different views for these wiki pages, so a `/view`
+tree is dedicated to this mission :
+
+ /view
+ |
+ |- dev
+ | |- d1.mdwn
+ | |- d2.mdwn
+ | |-...
+ |
+ |- howto
+ |- u1.mdwn
+ |- u2.mdwn
+ |- ...
+
+... where e.g. `/view/dev/d1` lists a subset (depending on other tags)
+of the pages tagged d1.
+
+My current plan is :
+
+- thanks to the edittemplate plugin, `/view/dev/*` and `/view/howto/*` would contain respectively `\[[!template id=dev_direction]]` and `\[[!template id=howto_usage]]`
+- `/templates/dev_direction.mdwn` and `/templates/howto_usage.mdwn` would use `\[[!map ...]]` directives to build their views
+
+# My issue
+
+Such map directives would look something like the following (more
+complicated, actually, but let's focus on my current issue) :
+
+ \[[!map pages="bricks/* and link(tag/usage/<TMPL_VAR BASENAME>)"]]
+
+Where `BASENAME` value would be, e.g., `u1` or `d2`, depending on the
+page inserting the template. But `BASENAME` does not exist. I found
+that `<TMPL_VAR PAGE>` is replaced with the full path to the page, but
+I did not found how to get the page's basename in a template included
+with a `\[[!template id=...]]` directive.
+
+Any idea ?
+
+I guess it would be possible to provide the templates inserted by the
+template plugin with more `TMPL_VAR` variables, but I don't know ikiwiki
+codebase well, so I don't know how hard it would be.
+
+I sure could write a ad-hoc plugin that would use the pagetemplate
+hook to add a custom `<TMPL_LOOP>` selector I could use in my
+templates, or another one that would use the filter hook to add the
+needed `\[[!map ...]]` where it belongs to, but since ikiwiki's
+preprocessor directives already *almost* do what I need, I'd like to
+avoid the ad-hoc plugin solution.
+
+(Adding a parameter such as `name=d1` in every `/view/dev/d*.mdwn` and
+`/view/howto/u*.mdwn` page is not an option : I want to factorize the
+most possible of these pages.
+
+> The following patch adds a `basename` `TMPL_VAR` variable that can be
+> used in the templates inserted by \[[!template plugin]] :
+
+> diff --git a/IkiWiki/Plugin/template.pm b/IkiWiki/Plugin/template.pm
+> index a6e34fc..bb9dd8d 100644
+> --- a/IkiWiki/Plugin/template.pm
+> +++ b/IkiWiki/Plugin/template.pm
+> @@ -57,6 +57,8 @@ sub preprocess (@) {
+> }
+> }
+>
+> + $template->param("basename" => (split("/", $params{page}))[-1]);
+> +
+> return IkiWiki::preprocess($params{page}, $params{destpage},
+> IkiWiki::filter($params{page}, $params{destpage},
+> $template->output));
+>
+> -- intrigeri
+
+> Thanks for taking the trouble to develop a patch. [[done]] --[[Joey]]
+
+>> Thanks :) -- intrigeri
>>>[xtermin.us rather than localhost](http://xtermin.us/git/?p=website.git;a=blob;f=plugins/googlesitemap.pm) is 404 now.
>>> -- weakish
+There is a [sitemap XML standard](http://www.sitemaps.org/protocol.php) that ikiwiki needs to generate for.
-According to [Google Webmaster tools](https://www.google.com/webmasters/tools/), my site isn't indexed for weeks at a time. Since I [blog](http://webconverger.org/blog/) every couple of days, that doesn't work. Yes I do have pingurl configured which [Google reader](http://reader.google.com/) does pick up quickly, but **not** the general search results from Google.
+# Google Webmaster tools and RSS
-There is a [sitemap XML standard](http://www.sitemaps.org/protocol.php) that ikiwiki needs to generate for.
+On [Google Webmaster tools](https://www.google.com/webmasters/tools) you can substitute an RSS feed as a sitemap. Do not use Atom as if you have malformed XHTML it will fail to parse and you will get a ERROR message like so:
+
+ We were unable to read your Sitemap. It may contain an entry we are unable to recognize. Please validate your Sitemap before resubmitting.
+
+[Google should grok feeds as sitemaps.](http://www.google.com/support/webmasters/bin/answer.py?answer=34654) Or rather [[plugins/inline]] should be improved to support the [sitemap protocol](http://sitemaps.org/protocol.php) natively.
-Update: I've since discovered under [Google Webmaster tools 'Subscriber stats'](https://www.google.com/webmasters/tools/subscriberstats), you can tell Google to treat a feed as a sitemap. Therefore in many cases just submitting your [[ikiwiki/blog/]]'s feed will be enough for Google to start better indexing your ikiwiki site.
+-- [[Hendry]]
--- /dev/null
+Xapian supports indexing pdfs, openoffice docs, etc. It would be nice if
+the search plugin would index these documents and optionally allow their
+exclusion.
+
+[[!tag wishlist]]
--- /dev/null
+Some OpenIDs seen in the IkiWiki git history are displayed poorly in [[RecentChanges]], including mine :-) (`http://smcv.pseudorandom.co.uk/`, shown as `smcv.pseudorandom [co.uk]`)
+
+My `openid` branch on <http://git.pseudorandom.co.uk/> improves on a couple of cases and adds a regression test. --[[smcv]]
+
+[[!tag patch done]]
index 59eabb6..82913ba 100644
--- a/IkiWiki/Plugin/inline.pm
+++ b/IkiWiki/Plugin/inline.pm
- @@ -229,6 +229,7 @@ sub preprocess_inline (@) { #{{{
+ @@ -229,6 +229,7 @@ sub preprocess_inline (@) {
$template->param(content => $content);
}
$template->param(pageurl => urlto(bestlink($params{page}, $page), $params{destpage}));
See also: [[bugs/tags_base_dir_not_used_when_creating_new_tags]]
-[[tag wishlist]]
+[[!tag wishlist]]
+
+[[done]]
--- /dev/null
+Please don't shoot me for asking:
+
+Could we have an ikiwiki mailing list?
+
+Here's an example use case:
+I want to discuss building a feature. Such discussion could happen on the wiki, but I would prefer to---at the least---be able to email ikiwiki developers and ask them to participate in this particular discussion.
+
+Does this sound okay?
+
+---[[JosephTurian]]
+
+[[!tag wishlist]]
+
+> People ask for this from time to time, but I personally prefer not to be
+> on an ikiwiki mailing list, because limiting public ikiwiki discussion to
+> this wiki helps make ikiwiki a better platform for discussion. So some
+> (most?) active ikiwiki people subscribe to recentchanges, or to the
+> todo/bugs/forum feeds, or to some other feed they create on their user page.
+> And there's work on making the discussion pages more structured, on
+> accepting comments sent via mail, etc. --[[Joey]]
--- /dev/null
+The current example ikiwiki.setup file has a number of options included, but commented out. This is standard. Unfortunately there are two standards for the settings of those commented out options:
+
+ - Have the commented out options showing the default setting, or
+ - Have the commented out options showing the most common alternate setting.
+
+Each of these has its advantages. The first makes it clear what the default setting is. The second makes it easy to switch the option on -- you just uncomment the option.
+
+My issue with ikiwiki's example setup file is that it doesn't appear to be consistent. Looking at the 'svn' entries (the first set of rcs entries), we see that
+
+ svnpath => "trunk",
+
+is an example of the first type, but
+
+ rcs => "svn",
+
+is an example of the second type.
+
+I think things could be improved if a clear decision was made here. Most of the settings seem to be of the second type. Perhaps all that is needed is for settings of the first type to grow a comment:
+
+ svnpath => "trunk", #default
+
+What do others think?
+
+> I agree, and I'll take a patch.
+>
+> I may not work on it myself, since I have some
+> [[interesting_ideas|online_configuration]] that would let ikiwiki
+> generate a setup file for you, rather than having to keep maintain the
+> current example.
+>
+> And.. [[done]].. setup files are now generated with `--dumpsetup`, based on
+> the built-in defaults, and commented options show an example
+> setting, not a default. --[[Joey]]
--- /dev/null
+The [[plugins/teximg]] plugin currently has a TODO in the source code to make the preamble configurable. The included [[patch]] makes this change.
+
+The patch also makes some other changes:
+
+ - The default latex preamble is changed to the international standard `article` class from the European `scrartcl` class.
+ - Removed the non-standard `mhchem` package from the default preamble.
+ - Allow the use of `dvipng` rather than `dvips` and `convert` (`convert` is not a standard part of a latex install). This is configurable.
+
+-- [[Will]]
+
+> I like making this configurable. I do fear that changing what's included
+> by default could break some existing uses of teximg? That needs to be
+> considered, and either the breakage documented in NEWS, or avoided. Also,
+> if mchem is dropped, I think the suggests on texlive-science in
+> debian/control should probably go? --[[Joey]]
+
+>> Yes, changing the defaults could break some existing uses. I think in
+>> this case, documenting in NEWS and dropping texlive-science is the
+>> best option. In fact, NEWS should probably document the config
+>> setting to return things to how they were.
+>>
+>> The reason I prefer dropping `mchem` rather than keeping it is that `mchem`
+>> is non-standard. Now that things are configurable and it is easy to
+>> add in if you want it, having only standard packages by default is a
+>> good thing. Here is a proposed NEWS entry:
+
+File: TexImg standard preamble changed
+
+The [[plugins/teximg]] [[plugin]] now has a configurable LaTeX preamble.
+As part of this change the `mchem` LaTeX package has been removed from
+the default LaTeX preamble as it wasn't included in many TeX installations.
+
+The previous behaviour can be restored by adding the following to your ikiwiki setup:
+
+ teximg_prefix => '\documentclass{scrartcl}
+ \usepackage[version=3]{mhchem}
+ \usepackage{amsmath}
+ \usepackage{amsfonts}
+ \usepackage{amssymb}
+ \pagestyle{empty}
+ \begin{document}',
+
+In addition, the rendering mechanism has been changed to use `dvipng` by default.
+If you would like to return to the old rendering mechanism using `dvips` and `convert`
+then you should add the following line to your ikiwiki setup:
+
+ teximg_dvipng => 0,
+
+The LaTeX postfix is unchanged, but is also now configurable using `teximg_postfix`.
+Happy TeXing.
+
+>> I think that about covers it. -- [[Will]]
+
+ diff --git a/IkiWiki/Plugin/teximg.pm b/IkiWiki/Plugin/teximg.pm
+ index 369c108..8c3379f 100644
+ --- a/IkiWiki/Plugin/teximg.pm
+ +++ b/IkiWiki/Plugin/teximg.pm
+ @@ -10,6 +10,18 @@ use File::Temp qw(tempdir);
+ use HTML::Entities;
+ use IkiWiki 2.00;
+
+ +my $default_prefix = <<EOPREFIX
+ +\\documentclass{article}
+ +\\usepackage{amsmath}
+ +\\usepackage{amsfonts}
+ +\\usepackage{amssymb}
+ +\\pagestyle{empty}
+ +\\begin{document}
+ +EOPREFIX
+ +;
+ +
+ +my $default_postfix = '\\end{document}';
+ +
+ sub import {
+ hook(type => "getsetup", id => "teximg", call => \&getsetup);
+ hook(type => "preprocess", id => "teximg", call => \&preprocess);
+ @@ -21,6 +33,26 @@ sub getsetup () {
+ safe => 1,
+ rebuild => undef,
+ },
+ + teximg_dvipng => {
+ + type => "boolean",
+ + description => "Should teximg use dvipng to render, or dvips and convert?",
+ + safe => 0,
+ + rebuild => 0,
+ + },
+ + teximg_prefix => {
+ + type => "string",
+ + example => $default_prefix,
+ + description => "LaTeX prefix for teximg plugin",
+ + safe => 0, # Not sure how secure LaTeX is...
+ + rebuild => 1,
+ + },
+ + teximg_postfix => {
+ + type => "string",
+ + example => $default_postfix,
+ + description => "LaTeX postfix for teximg plugin",
+ + safe => 0, # Not sure how secure LaTeX is...
+ + rebuild => 1,
+ + },
+ }
+
+ sub preprocess (@) {
+ @@ -105,25 +137,35 @@ sub gen_image ($$$$) {
+ my $digest = shift;
+ my $imagedir = shift;
+
+ - #TODO This should move into the setup file.
+ - my $tex = '\documentclass['.$height.'pt]{scrartcl}';
+ - $tex .= '\usepackage[version=3]{mhchem}';
+ - $tex .= '\usepackage{amsmath}';
+ - $tex .= '\usepackage{amsfonts}';
+ - $tex .= '\usepackage{amssymb}';
+ - $tex .= '\pagestyle{empty}';
+ - $tex .= '\begin{document}';
+ + if (!defined $config{teximg_prefix}) {
+ + $config{teximg_prefix} = $default_prefix;
+ + }
+ + if (!defined $config{teximg_postfix}) {
+ + $config{teximg_postfix} = $default_postfix;
+ + }
+ + if (!defined $config{teximg_dvipng}) {
+ + # TODO: Can we detect whether dvipng or convert is in the path?
+ + $config{teximg_dvipng} = 1;
+ + }
+ +
+ + my $tex = $config{teximg_prefix};
+ $tex .= '$$'.$code.'$$';
+ - $tex .= '\end{document}';
+ + $tex .= $config{teximg_postfix};
+ + $tex =~ s!\\documentclass{article}!\\documentclass[${height}pt]{article}!g;
+ + $tex =~ s!\\documentclass{scrartcl}!\\documentclass[${height}pt]{scrartcl}!g;
+
+ my $tmp = eval { create_tmp_dir($digest) };
+ if (! $@ &&
+ - writefile("$digest.tex", $tmp, $tex) &&
+ - system("cd $tmp; latex --interaction=nonstopmode $tmp/$digest.tex > /dev/null") == 0 &&
+ - system("dvips -E $tmp/$digest.dvi -o $tmp/$digest.ps 2> $tmp/$digest.log") == 0 &&
+ - # ensure destination directory exists
+ - writefile("$imagedir/$digest.png", $config{destdir}, "") &&
+ - system("convert -density 120 -trim -transparent \"#FFFFFF\" $tmp/$digest.ps $config{destdir}/$imagedir/$digest.png > $tmp/$digest.log") == 0) {
+ + writefile("$digest.tex", $tmp, $tex) &&
+ + system("cd $tmp; latex --interaction=nonstopmode $tmp/$digest.tex > /dev/null") == 0 &&
+ + # ensure destination directory exists
+ + writefile("$imagedir/$digest.png", $config{destdir}, "") &&
+ + (($config{teximg_dvipng} &&
+ + system("dvipng -D 120 -bg Transparent -T tight -o $config{destdir}/$imagedir/$digest.png $tmp/$digest.dvi > $tmp/$digest.log") == 0
+ + ) ||
+ + (!$config{teximg_dvipng} &&
+ + system("dvips -E $tmp/$digest.dvi -o $tmp/$digest.ps 2> $tmp/$digest.log") == 0 &&
+ + system("convert -density 120 -trim -transparent \"#FFFFFF\" $tmp/$digest.ps $config{destdir}/$imagedir/$digest.png > $tmp/$digest.log") == 0))) {
+ return 1;
+ }
+ else {
+
+[[done]]
*[Kyle](http://kitenet.net/~kyle/)=*
+> Took a bit too long, but [[done]] now. --[[Joey]]
+
----
The MediaWiki moving/renaming mechanism is pretty nice. It's easy to get a list of pages that point to the current page. When renaming a page it sticks a forwarding page in the original place. The larger the size of the wiki the more important organization tools become.
>
> This could also be implemented using a combination of raw inline and meta
> to change the title (add a "redirected from etc." page. This could be done
-> with a plugin. A redirect page would be [[redirect page="newpage"]].
+> with a plugin. A redirect page would be [[!redirect page="newpage"]].
> But then if you click "edit" on this redirect page, you won't be able
> to edit the new page, only the call to redirect.
> --Ethan
-----
-[[tag patch]]
-
-This is my second cut at a feature like that requested here.
-It can also be found [here](http://ikidev.betacantrips.com/patches/move.patch).
-
-A few shortcomings exist:
-
-* No precautions whatsoever are made to protect against race conditions or failures
- in the rcs\_move function. I didn't even do the `cgi_editpage` thing where I hold
- the lock and render afterwards (mostly because the copy I was editing was not
- up-to-date enough to have that code). Although FAILED_SAVE is in movepage.tmpl,
- no code activates it yet.
-* Some code is duplicated between cgi\_movepage and cgi\_editpage, as well
- as rcs\_commit and rcs\_move.
-* The user interface is pretty lame. I couldn't figure out a good way to let
- the user specify which directory to move things to without implementing a
- FileChooser thing.
-* No redirect pages like those mentioned on [[todo/Moving_Pages]] exist yet,
- so none are created.
-* I added a Move link to page.tmpl but it may belong better someplace else --
- maybe editpage.tmpl? Not sure.
-* from is redundant with page so far -- but since the Move links could someday
- come from someplace other than the page itself I kept it around.
-* If I move foo.mdwn to bar.mdwn, foo/* should move too, probably.
-
-> Looks like a good start, although I agree about many of the points above,
-> and also feel that something needs to be done about rcses that don't
-> implement a move operation -- falling back to an add and delete.
-> --[[Joey]]
-
-Hmm. Shouldn't that be done on a by-RCS basis, though? (i.e. implemented
-by backends in the `rcs_move` function)
-
-> Probably, yes, but maybe there's a way to avoid duplicating code for that
-> in several of them.
-
-Also, how should ikiwiki react if a page is edited (say, by another user)
-before it is moved? Bail, or shrug and proceed?
-
-> The important thing is to keep in mind that the page could be edited,
-> moved, deleted, etc in between the user starting the move and the move
-> happening. So, the code really needs to deal with all of these cases in
-> some way. It seems fine to me to go ahead with the move even if the page
-> was edited. If the page was deleted or moved, it seems reasonable to exit
-> with an error.
-
- diff -urNX ignorepats ikiwiki/IkiWiki/CGI.pm ikidev/IkiWiki/CGI.pm
- --- ikiwiki/IkiWiki/CGI.pm 2007-02-14 18:17:12.000000000 -0800
- +++ ikidev/IkiWiki/CGI.pm 2007-02-22 18:54:23.194982000 -0800
- @@ -561,6 +561,106 @@
- }
- } #}}}
-
- +sub cgi_movepage($$) {
- + my $q = shift;
- + my $session = shift;
- + eval q{use CGI::FormBuilder};
- + error($@) if $@;
- + my @fields=qw(do from rcsinfo page newdir newname comments);
- + my @buttons=("Rename Page", "Cancel");
- +
- + my $form = CGI::FormBuilder->new(
- + fields => \@fields,
- + header => 1,
- + charset => "utf-8",
- + method => 'POST',
- + action => $config{cgiurl},
- + template => (-e "$config{templatedir}/movepage.tmpl" ?
- + {template_params("movepage.tmpl")} : ""),
- + );
- + run_hooks(formbuilder_setup => sub {
- + shift->(form => $form, cgi => $q, session => $session);
- + });
- +
- + decode_form_utf8($form);
- +
- + # This untaint is safe because if the page doesn't exist, bail.
- + my $page = $form->field('page');
- + $page = possibly_foolish_untaint($page);
- + if (! exists $pagesources{$page}) {
- + error("page does not exist");
- + }
- + my $file=$pagesources{$page};
- + my $type=pagetype($file);
- +
- + my $from;
- + if (defined $form->field('from')) {
- + ($from)=$form->field('from')=~/$config{wiki_file_regexp}/;
- + }
- +
- + $form->field(name => "do", type => 'hidden');
- + $form->field(name => "from", type => 'hidden');
- + $form->field(name => "rcsinfo", type => 'hidden');
- + $form->field(name => "newdir", type => 'text', size => 80);
- + $form->field(name => "page", value => $page, force => 1);
- + $form->field(name => "newname", type => "text", size => 80);
- + $form->field(name => "comments", type => "text", size => 80);
- + $form->tmpl_param("can_commit", $config{rcs});
- + $form->tmpl_param("indexlink", indexlink());
- + $form->tmpl_param("baseurl", baseurl());
- +
- + if (! $form->submitted) {
- + $form->field(name => "rcsinfo", value => rcs_prepedit($file),
- + force => 1);
- + }
- +
- + if ($form->submitted eq "Cancel") {
- + redirect($q, "$config{url}/".htmlpage($page));
- + return;
- + }
- +
- + if (! $form->submitted || ! $form->validate) {
- + check_canedit($page, $q, $session);
- + $form->tmpl_param("page_select", 0);
- + $form->field(name => "page", type => 'hidden');
- + $form->field(name => "type", type => 'hidden');
- + $form->title(sprintf(gettext("moving %s"), pagetitle($page)));
- + my $pname = basename($page);
- + my $dname = dirname($page);
- + if (! defined $form->field('newname') ||
- + ! length $form->field('newname')) {
- + $form->field(name => "newname",
- + value => pagetitle($pname, 1), force => 1);
- + }
- + if (! defined $form->field('newdir') ||
- + ! length $form->field('newdir')) {
- + $form->field(name => "newdir",
- + value => pagetitle($dname, 1), force => 1);
- + }
- + print $form->render(submit => \@buttons);
- + }
- + else{
- + # This untaint is safe because titlepage removes any problematic
- + # characters.
- + my ($newname)=$form->field('newname');
- + $newname=titlepage(possibly_foolish_untaint($newname));
- + my ($newdir)=$form->field('newdir');
- + $newdir=titlepage(possibly_foolish_untaint($newdir));
- + if (! defined $newname || ! length $newname || file_pruned($newname, $config{srcdir}) || $newname=~/^\//) {
- + error("bad page name");
- + }
- + check_canedit($page, $q, $session);
- +
- + my $newpage = ($newdir?"$newdir/":"") . $newname;
- + my $newfile = $newpage . ".$type";
- + my $message = $form->field('comments');
- + unlockwiki();
- + rcs_move($file, $newfile, $message, $form->field("rcsinfo"),
- + $session->param("name"), $ENV{REMOTE_ADDR});
- + redirect($q, "$config{url}/".htmlpage($newpage));
- + }
- +}
- +
- sub cgi_getsession ($) { #{{{
- my $q=shift;
-
- @@ -656,6 +756,9 @@
- elsif (defined $session->param("postsignin")) {
- cgi_postsignin($q, $session);
- }
- + elsif ($do eq 'move') {
- + cgi_movepage($q, $session);
- + }
- elsif ($do eq 'prefs') {
- cgi_prefs($q, $session);
- }
- diff -urNX ignorepats ikiwiki/IkiWiki/Rcs/svn.pm ikidev/IkiWiki/Rcs/svn.pm
- --- ikiwiki/IkiWiki/Rcs/svn.pm 2007-01-27 16:04:48.000000000 -0800
- +++ ikidev/IkiWiki/Rcs/svn.pm 2007-02-22 01:51:29.923626000 -0800
- @@ -60,6 +60,34 @@
- }
- } #}}}
-
- +sub rcs_move ($$$$;$$) {
- + my $file=shift;
- + my $newname=shift;
- + my $message=shift;
- + my $rcstoken=shift;
- + my $user=shift;
- + my $ipaddr=shift;
- + if (defined $user) {
- + $message="web commit by $user".(length $message ? ": $message" : "");
- + }
- + elsif (defined $ipaddr) {
- + $message="web commit from $ipaddr".(length $message ? ": $message" : "");
- + }
- +
- + chdir($config{srcdir}); # svn merge wants to be here
- +
- + if (system("svn", "move", "--quiet",
- + "$file", "$newname") != 0) {
- + return 1;
- + }
- + if (system("svn", "commit", "--quiet",
- + "--encoding", "UTF-8", "-m",
- + possibly_foolish_untaint($message)) != 0) {
- + return 1;
- + }
- + return undef # success
- +}
- +
- sub rcs_commit ($$$;$$) { #{{{
- # Tries to commit the page; returns undef on _success_ and
- # a version of the page with the rcs's conflict markers on failure.
- diff -urNX ignorepats ikiwiki/IkiWiki/Render.pm ikidev/IkiWiki/Render.pm
- --- ikiwiki/IkiWiki/Render.pm 2007-02-14 17:00:05.000000000 -0800
- +++ ikidev/IkiWiki/Render.pm 2007-02-22 18:30:00.451755000 -0800
- @@ -80,6 +80,7 @@
-
- if (length $config{cgiurl}) {
- $template->param(editurl => cgiurl(do => "edit", page => $page));
- + $template->param(moveurl => cgiurl(do => "move", page => $page));
- $template->param(prefsurl => cgiurl(do => "prefs"));
- if ($config{rcs}) {
- $template->param(recentchangesurl => cgiurl(do => "recentchanges"));
- diff -urNX ignorepats ikiwiki/templates/movepage.tmpl ikidev/templates/movepage.tmpl
- --- ikiwiki/templates/movepage.tmpl 1969-12-31 16:00:00.000000000 -0800
- +++ ikidev/templates/movepage.tmpl 2007-02-22 18:40:39.751763000 -0800
- @@ -0,0 +1,44 @@
- +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- +<html>
- +<head>
- +<base href="<TMPL_VAR BASEURL>" />
- +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- +<title><TMPL_VAR FORM-TITLE></title>
- +<link rel="stylesheet" href="<TMPL_VAR BASEURL>style.css" type="text/css" />
- +<link rel="stylesheet" href="<TMPL_VAR BASEURL>local.css" type="text/css" />
- +<TMPL_IF NAME="FAVICON">
- +<link rel="icon" href="<TMPL_VAR BASEURL><TMPL_VAR FAVICON>" type="image/x-icon" />
- +</TMPL_IF>
- +</head>
- +<body>
- +<TMPL_IF NAME="FAILED_SAVE">
- +<p>
- +<b>Failed to save your changes.</b>
- +</p>
- +<p>
- +Your changes were not able to be saved to disk. The system gave the error:
- +<blockquote>
- +<TMPL_VAR ERROR_MESSAGE>
- +</blockquote>
- +Your changes are preserved below, and you can try again to save them.
- +</p>
- +</TMPL_IF>
- +<TMPL_VAR FORM-START>
- +<div class="header">
- +<span><TMPL_VAR INDEXLINK>/ <TMPL_VAR FORM-TITLE></span>
- +</div>
- +<TMPL_VAR FIELD-DO>
- +<TMPL_VAR FIELD-FROM>
- +<TMPL_VAR FIELD-RCSINFO>
- +<TMPL_VAR FIELD-PAGE>
- +New location: <TMPL_VAR FIELD-NEWDIR>/ <TMPL_VAR FIELD-NEWNAME>
- +<br />
- +<TMPL_IF NAME="CAN_COMMIT">
- +Optional comment about this change:<br />
- +<TMPL_VAR FIELD-COMMENTS><br />
- +</TMPL_IF>
- +<input id="_submit" name="_submit" type="submit" value="Rename Page" /><input id="_submit_2" name="_submit" type="submit" value="Cancel" />
- +<TMPL_VAR FORM-END>
- +</body>
- +</html>
- diff -urNX ignorepats ikiwiki/templates/page.tmpl ikidev/templates/page.tmpl
- --- ikiwiki/templates/page.tmpl 2006-12-28 12:27:01.000000000 -0800
- +++ ikidev/templates/page.tmpl 2007-02-22 01:52:33.078464000 -0800
- @@ -32,6 +32,9 @@
- <TMPL_IF NAME="EDITURL">
- <li><a href="<TMPL_VAR EDITURL>">Edit</a></li>
- </TMPL_IF>
- +<TMPL_IF NAME="MOVEURL">
- +<li><a href="<TMPL_VAR MOVEURL>">Move</a></li>
- +</TMPL_IF>
- <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.)
+
+Hmm, unless it saves the edit state and reloads it later, while using a separate
+form. Which seems to solve other problems, so I think is the way to go.
+
+## 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.
+
+(For values of "simplest" that don't include the pain of dealing with all
+the changed links on subpages.. as well as issues like pagespecs that
+continue to match the old subpages, and cannot reasonably be auto-converted
+to use the new, etc, etc... So still undecided about this.)
+
+When deleting `foo`, I don't think SubPages should be deleted. The
+potential for mistakes and abuse is too large. Deleting Discussion page
+might be a useful exception.
+
+TODO: Currently, subpages are not addressed.
+
+## 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.
+
+The rename plugin can add a "rename" hook, which other plugins can use to
+update links &etc. The hook would be passed page content, the old and new
+link names, and would modify the content and return it. At least the link
+plugin should have such a hook.
+
+After calling the "rename" hook, and rendering the wiki, the rename plugin
+can check to see what links remain pointing to the old page. There could
+still be some, for example, CamelCase links probably won't be changed; img
+plugins and others contain logical links to the file, etc. The user can be
+presented with a list of all the pages that still have links to the old
+page, and can manually deal with them.
+
+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.
+
+lWhen deleting/renaming attachments, the `allowed_attachments` PageSpec
+is checked too.
+
+## RCS
+
+Three new functions are added to the RCS interface:
+
+* `rcs_remove(file)`
+* `rcs_rename(old, new)`
+* `rcs_commit_staged(message, user, ip)`
+
+See [[rcs_updates_needed_for_rename_and_remove]].
+
+## conflicts
+
+Cases to consider:
+
+* 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.
+ Update: In my current code, alice's deletion will fail if the file was
+ moved or deleted in the meantime; if the file was modified since alice
+ clicked on the delete button, the modifications will be deleted too. I
+ think this is acceptable.
+* 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.
+ Update: Again here, there's no conflict, but the delete succeeds. Again,
+ basically acceptible.
+* 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..
+ Update: It will display an error to the second one that the page doesn't
+ exist.
+* 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.
+ Update: Bob wins.
+* 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.
+ Update: it does
+* Alice opens edit UI for a page; Bob makes a modification; Alice
+ clicks rename button and confirms rename. Seems same as previous case.
+ Update: check
+* 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.
+ Update: check, that happens
+* 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.
+ Update: Behavior is the same as if Alice renamed the page and Bob created
+ a new page with the old name. Seems acceptable, though could be mildly
+ confusing to Bob (or Alice).
+* 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.
+ Update: That should happen. Haven't tested this case yet to make sure.
+* 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.)
+ Update: Bob gets an error message.
+* 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?
+ Update: Meh. It's certianly not ideal; if Bob tries to save the page he
+ uploaded the attachment to, he'll get a message about it having been
+ deleted/renamed, and he can try to figure out what to do... :-/
+* I don't know if this is a conflict, but it is an important case to consider;
+ you need to make sure that there are no security holes. You dont want
+ someone to be able to rename something to <code>/etc/passwd</code>.
+ I think it would be enough that you cannot rename to a location outside
+ of srcdir, you cannot rename to a location that you wouldn't be able
+ to edit because it is locked, and you cannot rename to an existing page.
+
+ > Well, there are a few more cases (like not renaming to a pruned
+ > filename, and not renaming _from_ a file that is not a known source
+ > file or is locked), but yes, that's essentially it.
+ >
+ > PS, the first thing I do to any
+ > web form is type /etc/passwd and ../../../../etc/passwd into it. ;-) --[[Joey]]
* The inability to use spaces in wikilinks or link text
* The requirement to use a trailing space on a preprocessor directive
- with no arguments, such as `\[[toc ]]`
+ with no arguments, such as `\[[!toc ]]`
--[[JoshTriplett]]
-[[done]] in version 2.21, using the '!'-prefixed syntax. --[[JoshTriplett]]
\ No newline at end of file
+[[done]] in version 2.21, using the '!'-prefixed syntax. --[[JoshTriplett]]
Err, is this really fixed in 2.21? I can't find it anywhere in 2.32.3
(debian unstable)
+
+-----
+
+I just did a `--dumpsetup` with the current version from the Git repository
+and the default option is
+
+ # use '!'-prefixed preprocessor directives?
+ prefix_directives => 0,
+
+My impression was that this should be enabled by default now. --[[JasonBlevins]]
+
+> As stated in `debian/NEWS`:
+>> For backward compatibility with existing wikis,
+>> refix_directives currently defaults to false. In ikiwiki 3.0,
+>> prefix_directives will default to true [...]
+> --[[intrigeri]]
+
[[plugins/search]] could provide [OpenSearch](http://www.opensearch.org/)
metadata. Various software supports OpenSearch (see the Wikipedia article on
-[[wikipedia OpenSearch]]); in particular, browsers like Firefox and Iceweasel
+[[!wikipedia OpenSearch]]); in particular, browsers like Firefox and Iceweasel
will automatically discover an OpenSearch search and offer it in the search
box.
-Currently, the page title (either the name of the page or the title specified with `\[[meta title="..."]]`) shows up in a `<div class="header">`. I tend to follow the [w3c guideline recommending the use of h1 for the title](http://www.w3.org/QA/Tips/Use_h1_for_Title); for this purpose, how about an option to make the page title an `<h1 class="header">`, and shift the markdown headings down by one (making # an h2, ## an h3, etc; or alternatively making # equivalent to `\[[meta title="..."]]`)?
+Currently, the page title (either the name of the page or the title specified with `\[[!meta title="..."]]`) shows up in a `<div class="header">`. I tend to follow the [w3c guideline recommending the use of h1 for the title](http://www.w3.org/QA/Tips/Use_h1_for_Title); for this purpose, how about an option to make the page title an `<h1 class="header">`, and shift the markdown headings down by one (making # an h2, ## an h3, etc; or alternatively making # equivalent to `\[[!meta title="..."]]`)?
> The reason I don't use a h1 for the navbar is that while it incorporates
> the page title, it's not just a page title, it has the links to parent pages.
> way, # is reserved for h1 if you choose to use headers in your page. --[[Joey]]
[[done]]
+
+> For anyone interested, I've written a small plugin called [h1title][] that does the
+> latter, making `#` (only when on the first line) set the page title, removing it from
+> the page body. --[[JasonBlevins]], October 22, 2008
+
+ [h1title]: http://code.jblevins.org/ikiwiki/plugins.git/plain/h1title.pm
[[madduck]]: Update: I did try setting `templates` in `ikiwiki.setup` but could not get it to work. Then I found in the code that ikiwiki already checks that dir before the `/usr/share/ikiwiki` one, and tried it again, and now it works... sorry.
-Thus [[taglink done]].
\ No newline at end of file
+Thus [[!taglink done]].
\ No newline at end of file
> sidebar could be done as you describe using .shtml. --[[Joey]]
[[wishlist]]
+
+> I have a plan for a way to avoid unecessary rebuilds caused by the
+> sidebar. The idea is to use wikistate to store what a sidebar renders to.
+> Then in the needsbuild hook, render sidebar(s) and compare with their
+> previous stored rendering. If a sidebar's rendered content has changed,
+> then all pages that display that sidebar need to be forced to be rebuilt.
+>
+> Also, if there is no previous stored rendering for a sidebar, or
+> if there is a stored rendering for a sidebar page that no longer exists, then
+> the pages need to be rebuilt. (This should deal with the [[bugs/Building_a_sidebar_does_not_regenerate_the_subpages]] bug.
+>
+> This would also save significant time, since the stored sidebar rendering
+> could just be dumped into the page by the pagetemplate hook. Current code
+> re-loads and renders the same sidebar file for every page built!
+>
+> The sticky part is (relative) links on the sidebar. These would need to
+> be modified somehow depending on the page that the sidebar is placed on,
+> to not break the link.
+>
+> Another wrinkle is changing subpage links on a sidebar. Suppose a sidebar
+> links to page `foo`. If page `bar/foo` exists, the sidebar on page bar will,
+> currently, link to that page, in preference to a toplevel `foo`.
+> If `bar/foo` is removed, it will update to link to `foo`. With the new
+> scheme, the stored sidebar rendering is not for page `foo`, and so
+> the change of the `bar/foo` link will not be noticed or acted on.
+> Granted, it's unlikely that anyone relies on the current behavior. You
+> generally want links on a sidebar to link to the same place on every page
+> that displays it. So finding some way to force all links on a sidebar to
+> be handled absolutely and documenting that would avoid this problem.
+>
+> So, one way to handle both the above problems would be to use the
+> pre-rendered sidebar for each page, but use a html parser to look for
+> links in it, and munge them to work as relative links on the page the
+> sidebar is being added to. Or, if the wiki's url is known, just do this
+> once when rendering the sidebar, adding the full url to the links.
+> (Maybe require `url` be set when using sidebar?)
+> --[[Joey]]
> I would really like for some additional TMP variables to be present in the rss template as well. For the inline page template, the CTIME TMPL_VAR results in nice phrases like: <q>Posted late Tuesday morning, November 13th, 2007</q>, and it would be neat to let the planet Debian people see that as well :-) Manoj
-[[tag wishlist]]
+[[!tag wishlist]]
rawurl => "http://localhost:8000//raw-file/tip/\[[file]]",
-> What I want to do when I want to see if the raw source is either
+> What I do when I want to see if the raw source is either
> click on the edit link, or click on history and navigate to it in the
> history browser (easier to do in viewvc than in gitweb, IIRC).
> Not that I'm opposed to the idea of a plugin that adds a Raw link
> --[[Joey]]
-[[tag wishlist]]
+>> In [[todo/source_link]], Will does this via the CGI instead of delegating
+>> to gitweb/etc. I think Will's patch is a good approach, and have improved
+>> on it a bit in a git branch.
+
+>>> Since that is merged in now, I'm marking this [[done]] --[[Joey]]
+
+[[!tag wishlist]]
--- /dev/null
+Links to the changed page on RecentChanges only show up if the cgi wrapper is
+enabled. It would be nice if links were also generated on wikis that do not use
+the cgi. [[svend]]
+
+> It would be, but doing so would make updating the recentchanges page for
+> each commit a lot slower, or would result in there often being broken
+> links there.
+>
+> The broken links would happen if a page is removed.
+>
+> The speed issue is that currently each individual change in the
+> recentchanges page is built just once, when the change is made, and the
+> html for it is reused thereafter. To avoid broken links, it would need to
+> regenerate each change's html on each commit. That's 100x the overhead.
+> (Perhaps it's possible to be smarter about which need generation tho.)
+>
+> The best way to approach this that I can see ATM is to use the
+> [[plugins/404]] plugin to handle the broken links and then recentchanges
+> could avoid explicitly using the CGI. But this doesn't meet your use case
+> of having no CGI.
+>
+> If you're willing to live with broken links to removed pages, I suppose
+> that could be made an option..
+> --[[Joey]]
+
+[[!tag wishlist]]
--- /dev/null
+I see OpenID more as an authentication technology than as a human-friendly identifier. It would be cool if, in addition to my identity URL, I could also associate a username with my account. I'd then use the URL to log in, but all changes would be associated with the username I provide. Additionally, I could sign changes with my username, possibly change my identity URL and set a password. It would be nice if I could use my identity URL for authentication convenience and actually be known as nolan or thewordnerd on my wikis, rather than the somewhat less human http://thewordnerd.info. :)
+
+Separating username from identity URL would also let me change the URL later. It would be nice, for instance, if I could assign a username to my account and change the identity to my preferred thewordnerd.info once delegation is supported, without the potential of losing access to my account and contributions. :)
+
+I see this being implemented in one of two possible ways. The easiest seems like it'd involve splitting the fields, doing a simple OpenID verification as is done today, then allow setting of username on the preferences page. When crediting a user for a change, call a function that returns either the username or, if it is null, the identity URL. Then, allow logging into the same account with the username, but only if the password is non-blank. That seems like the most minimal and least invasive way of making the change.
+
+A slightly more complex next step would be to request sreg from the provider and, if provided, automatically set the identity's username and email address from the provided persona. If username login to accounts with blank passwords is disabled, then you have the best of both worlds. Passwordless signin, human-friendly attribution, automatic setting of preferences.
+
+Unfortunately I don't speak Perl, so hopefully someone thinks these suggestions are good enough to code up. I've hacked on openid code in Ruby before, so hopefully these changes aren't all that difficult to implement. Even if you don't get any data via sreg, you're no worse off than where you are now, so I don't think there'd need to be much in the way of error/sanity-checking of returned data. If it's null or not available then no big deal, typing in a username is no sweat.
+
+[[!tag wishlist]]
-[[tag patch]]
+[[!tag patch plugins/calendar]]
Here's my next version of the patch - still a work in progress.
* If you specify an event preprocessor in a post, such as:
- [[event time="2008-06-24"]]
+ [[!event time="2008-06-24"]]
That date will be used instead of the post creation time when displaying the calendar.
my %cache;
my %linkcache;
@@ -32,6 +34,7 @@
- sub import { #{{{
+ sub import {
hook(type => "needsbuild", id => "version", call => \&needsbuild);
hook(type => "preprocess", id => "calendar", call => \&preprocess);
+ hook(type => "preprocess", id => "event", call => \&preprocess_event);
- } #}}}
+ }
- sub is_leap_year (@) { #{{{
+ sub is_leap_year (@) {
@@ -58,6 +61,7 @@
my $nmonth = $params{nmonth};
my $pyear = $params{pyear};
# finish off the week
@@ -304,6 +333,18 @@
return $calendar;
- } #}}}
+ }
- +sub preprocess_event (@) { #{{{
+ +sub preprocess_event (@) {
+ my %params=@_;
+ # if now time is given, use now
+ $params{begin} = localtime($time) unless defined $params{begin};
+ return "<!-- $params{begin} -->";
+} #}}
+
- sub preprocess (@) { #{{{
+ sub preprocess (@) {
my %params=@_;
$params{pages} = "*" unless defined $params{pages};
@@ -311,6 +352,8 @@
> I agree that a plugin would probably be more cumbersome, but it is very
> doable. It might look something like this:
- \[[link bar]]
+ \[[!link bar]]
- \[[link bar=VeryLongPageName]]
+ \[[!link bar=VeryLongPageName]]
>> This is, however, still missing specifying the link text, and adding that option would seem to me to complicate the plugin syntax a lot, unless support is added for the |-syntax for specifying a particular parameter to every plugin.
>> ... Returning to this, the syntax infact wouldn't be so bad with the |-syntax, given a short name for the plugin:
[[whatever|ref 1]]
- \[[ref 1=page_with_long_name]]
+ \[[!ref 1=page_with_long_name]]
>>> A way to do this that doesn't need hacking at the preprocessor syntax
>>> follows: --[[Joey]]
- \[[link bar=1]]
- \[[dest 1=page_with_long_name]]
+ \[[!link bar=1]]
+ \[[!dest 1=page_with_long_name]]
>>>> But this doesn't work so well for links that aren't valid keys. Such
>>>> as stuff with spaces in it. I'd like to be able to write any kind of
>>>>> You're right, and to fix that it could be turned around: --[[Joey]]
- \[[link 1=bar]]
- \[[dest 1=page_with_long_name]]
+ \[[!link 1=bar]]
+ \[[!dest 1=page_with_long_name]]
>> It also shouldn't be difficult to support non-wiki links in this same
>> way, so that you could still link everywhere in an uniform manner, as
--- /dev/null
+A quick [[patch]] to silence a [[rcs/monotone]] warning I started seeing:
+
+ diff --git a/IkiWiki/Plugin/monotone.pm b/IkiWiki/Plugin/monotone.pm
+ index 4b9be31..9d4e280 100644
+ --- a/IkiWiki/Plugin/monotone.pm
+ +++ b/IkiWiki/Plugin/monotone.pm
+ @@ -55,7 +55,7 @@ sub checkconfig () {
+ error("Monotone version too old, is $version but required 0.38");
+ }
+
+ - if (length $config{mtn_wrapper}) {
+ + if (defined $config{mtn_wrapper} && length $config{mtn_wrapper}) {
+ push @{$config{wrappers}}, {
+ wrapper => $config{mtn_wrapper},
+ wrappermode => (defined $config{mtn_wrappermode} ? $config{mtn_wrappermode} : "06755"),
+
+> Thanks, [[done]]
>
> IMHO, what you really want is [[Moving_pages]]. :-) --[[Joey]]
-[[tag wishlist]]
+>> This sounds like WONTFIX to me? --[[smcv]]
+
+[[!tag wishlist done]]
Perhaps ikiwiki should support XML-RPC-based blogging, using the [standard
MetaWeblog protocol](http://www.xmlrpc.com/metaWeblogApi). This would allow
-the use of applets like [[debpkg gnome-blog]] to post to an ikiwiki blog. The
+the use of applets like [[!debpkg gnome-blog]] to post to an ikiwiki blog. The
protocol supports multiple blog names, so one standard URL with page names as
blog names would work. --[[JoshTriplett]]
>> I'd love to see support for this and would be happy to contribute towards a bounty (say US$100) :-). [PmWiki](http://www.pmwiki.org/) has a plugin which [implements this](http://www.pmwiki.org/wiki/Cookbook/XMLRPC) in a way which seems fairly sensible as an end user. --[[AdamShand]]
-[[tag soc]]
+[[!tag soc]]
-[[tag wishlist]]
+[[!tag wishlist]]
-[[tag wishlist]]
+[[!tag wishlist]]
It'd be nice to be allowed to insert tabs into the textarea, as opposed to
having to insert 4-spaces for lists/etc. This would require JavaScript to
my blog to simply consist of all pages that have been tagged. That is,
I'd like to have my blog page look like this:
- \[[inline pages="link(tag/*)"]]
+ \[[!inline pages="link(tag/*)"]]
That doesn't work in ikiwiki 2.1, but I have it
[working](http://www.cworth.org/blog) with the following patch:
index 38aa46a..cd42e8d 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
- @@ -1082,10 +1082,15 @@ sub match_link ($$;@) { #{{{
+ @@ -1082,10 +1082,15 @@ sub match_link ($$;@) {
my $links = $IkiWiki::links{$page} or return undef;
return IkiWiki::FailReason->new("$page has no links") unless @$links;
my $bestlink = IkiWiki::bestlink($from, $link);
+ }
}
return IkiWiki::FailReason->new("$page does not link to $link");
- } #}}}
+ }
--
1.5.1.1.g6aead
--- /dev/null
+Page footers contain a list of links to the page and a list of tags applied to the page. The link list uses the full path to pages. However, the tag list contains only the basename of the tag pages. For instance, if I tag a page with person1/foo and person2/bar, the tag list will just list foo and bar without the necessary disambiguating prefixes.
+
+I think the tag list should always contain the full path to the tag, with the tagbase value removed.
+
+--[[JoshTriplett]]
+
+> What if tagbase is not used? I know this would clutter up the display of
+> my tags on several wikis, including this one. --[[Joey]]
--- /dev/null
+Not sure about this TODO, but here it is anyway...
+
+It would be nice to have unit tests for IkiWiki. This would make sure that we don't break things when adding more functionality.
+
+> mmm unit tests. --[[schmonz]]
+
+>> Ikiwiki has over 500 tests, most of them of the unit test variety. They
+>> are located in the 't' directory and are run by 'make test'. Most of the
+>> core ikiwiki functions are covered. Feel free to contribute more..
+>> --[[Joey]] [[done]]
--- /dev/null
+As noted in [[tips/untrusted_git_push]] an untrusted push capability was added recently, but only implemented in git.
+(See also [[todo/rcs_updates_needed]])
+
+This note describes (but does not implement) an approach for this with the [[rcs/monotone]] rcs backend.
+
+----
+
+Monotone behaves a little differently to git in its networking. Git allows anyone to try to push, and then
+check whether it is ok before finally accepting it. Monotone has no way to accept or reject revisions
+in this way. However, monotone does have the ability to mark revisions, and to ignore unmarked revisions.
+
+This marking capability can be used to achieve a somewhat similar effect to what happens with git. The
+problem with this is that anyone could put anything into the monotone database, and while this wouldn't
+affect ikiwiki, it seems bad to leave open, untrusted storage on the web.
+
+The Plan
+=====
+
+In the `note_netsync_revision_received` hook in the monotone server, have the server check to make sure
+that either a) the revision is signed by someone trusted or, b) the revision is checked using the same
+hook that git uses in `pre-receive`. If the revision passes the ikiwiki `pre-receive` check then the
+monotone hook signs the revision. This gives that revision the 'ikiwiki seal of approval'.
+
+You'll also want to update the monotone trust hooks to only trust revisions signed by trusted people, or
+ikiwiki.
+
+Now anyone can upload a revision, but only those signed by a trusted person, or which pass the ikiwiki
+check and so get signed by the ikiwiki key, will be seen by ikiwiki.
--- /dev/null
+I've put together an updated bug tracking example. This example requires some recent
+patches of mine. It requires [[todo/tracking_bugs_with_dependencies]],
+[[todo/Allow_edittemplate_to_set_file_type]] and the second [[patch]] in
+[[todo/structured_page_data]] (the data plugin, not the form plugin).
+
+You'll then want to add/replace the following files in the software project example. The
+heading is the name of the file. I've commented all the directives. Oh, and I don't
+have nice CSS for this yet. I did make sure that if I borrowed
+[Trac's](http://trac.edgewall.org/) css then it would display as nicely as theirs - the
+html is there if not the CSS.
+
+It might be worth adding some justification of what is going on here. The datatable
+and data directives generate a nice tabular form for the structured data. The HTML
+generated is the same as for Trac, except I've got fewer fields. Adding more is trivial.
+
+I use data directives rather than links because the data directive allows separating
+dependencies from links. We can specify 'bugs with all dependencies closed' without
+being confused by other links on the page.
+
+-- [[Will]]
+
+### templates/bug.mdwn
+
+ \[[!datatable class="bugtable" datalist="""
+ [[!data key="Reported by" link=""]] [[!data key="Owned by" link=""]]
+ [[!data key="Depends on"]]
+ """]]
+
+ ### Description
+
+ This is a bug that needs solving.
+
+ #### Steps to reproduce:
+
+ #### What I expect to happen:
+
+ #### What actually happens:
+
+ #### What I have tried to narrow it down:
+
+### bugs.mdwn
+
+ This is FooBar's bug list. Link bugs to \[[bugs/done]] when done.
+
+ \[[!inline pages="bugs and ! bugs" feeds=no postform=yes
+ postformtext="Report a bug:" rootpage="bugs"]]
+
+ \[[!edittemplate template="templates/bug" match="bugs/* and !*/Discussion" silent=yes]]
+
+ \[[!toggle id="all bugs" text="Show all bugs"]]
+
+ \[[!toggle id="open bugs" text="Show open bugs"]]
+
+ \[[!toggle id="ready bugs" text="Show ready bugs (open bugs with all dependencies closed)"]]
+
+ \[[!toggleable id="ready bugs" text="""
+ #### Ready Bugs
+
+ Open bugs with all dependencies closed.
+
+ [[!inline pages="define(~open, ./bugs/* and !./bugs/done and !link(done) and !*/Discussion)
+ and ~open and !data_link(Depends on,~open)" actions=yes archive=yes show=0]]
+ """]]
+
+ \[[!toggleable id="open bugs" text="""
+ #### Open Bugs
+
+ [[!inline pages="./bugs/* and !./bugs/done and !link(done)
+ and !*/Discussion" actions=yes archive=yes show=0]]
+ """]]
+
+ \[[!toggleable id="all bugs" text="""
+ #### All Bugs
+
+ [[!inline pages="./bugs/* and !./bugs/done and !*/Discussion"
+ actions=yes archive=yes show=0]]
+ """]]
+
+### bugs/needs_more_bugs.mdwn
+
+ \[[!datatable class="bugtable" datalist="""
+ [[!data key="Reported by" link="John"]] [[!data key="Owned by" link="Frank"]]
+ [[!data key="Depends on" link="bugs/fails_to_frobnicate"]]
+ """]]
+
+ ### Description
+
+ FooBar does not have enough bugs, which suggests that it's not a real Free
+ Software project. Please help create more bugs by adding code to FooBar!
+ :-)
+
+ #### Steps to reproduce:
+
+ Test frobnicate.
+
+ #### What I expect to happen:
+
+ It should fail.
+
+ #### What actually happens:
+
+ It works.
+
+ #### What I have tried to narrow it down:
+
+ I've added some code, but I'm not sure it was the right code.
+
+### bugs/fails_to_frobnicate.mdwn
+
+ \[[!datatable class="bugtable" datalist="""
+ [[!data key="Reported by" link="John"]] [[!data key="Owned by" link="Frank"]]
+ [[!data key="Depends on"]]
+ """]]
+
+ ### Description
+
+ FooBar, when used with the `--frob` option, fails to properly frobnicate
+ output.
+
+ > This is fixed in \[[news/version_1.0]]; marking this bug \[[done]].
+
+ #### Steps to reproduce:
+
+ Use FooBar with the `--frob` option.
+
+ #### What I expect to happen:
+
+ Lots of frobnication.
+
+ #### What actually happens:
+
+ Complete lack of frobnication
+
+ #### What I have tried to narrow it down:
+
+ Tested on Linux, MacOS and NetBSD.
+++ wiki-meta/perl/IkiWiki.pm Mon Jun 11 10:52:07 2007
@@ -205,7 +205,7 @@
- sub possibly_foolish_untaint ($) { #{{{
+ sub possibly_foolish_untaint ($) {
my $tainted=shift;
- my ($untainted)=$tainted=~/(.*)/;
+ my ($untainted)=$tainted=~/(.*)/s;
return $untainted;
- } #}}}
+ }
Modified: wiki-meta/perl/IkiWiki/Wrapper.pm
-Here is a patch [[tag patch]] to add a *forward*ing functionality
+Here is a patch [[!tag patch]] to add a *forward*ing functionality
to the [[`meta`_plugin|plugins/meta]].
> [[done]], with some changes --[[Joey]]
**OPT_DELAY** = delay=**D** | empty (*immediatelly*)
-\[[meta forward="**WHITHER**" **OPT_DELAY**]]
+\[[!meta forward="**WHITHER**" **OPT_DELAY**]]
# Extensions and Ideas
There is a problem though if this navbar were included in a sidebar (the logical place): if a page is updated, the navbar needs to be rebuilt which causes the sidebar to be rebuilt, which causes the whole site to be rebuilt. Unless we can subscribe only to title changes, this will be pretty bad...
--[[madduck]]
+
+> I've just written a plugin for a automatically created menu for use
+> [here](http://www.ff-egersdorf-wachendorf.de/). The source is at
+> [gitorious](http://gitorious.org/ikiwiki-plugins/automenu). The problem with
+> rebuilding remains unsolved but doesn't matter that much for me as I always
+> generate the web site myself, ie it's not really a wiki. --[[lnussel]]
+
[[!tag wishlist]]
When converting an existing blog to ikiwiki it would be useful to be able to preserve any existing UUIDs on posts, in order to [avoid flooding aggregators](/tips/howto_avoid_flooding_aggregators/).
-Also, it should be possible to change the canonical URL of a post, i.e. the atom `<link>` (e.g. leaving a redirector behind) while keeping the same UUID (so that aggregators don't get confused).
+Also, it should be possible to change the permalink (the Atom `<link>`) of a post (e.g. moving the content and leaving a redirector behind), while keeping the same Atom `<id>` (so that aggregators don't get confused).
-Ideally UUIDs for [blog posts](/ikiwiki/blog/) should be chosen when the post is created, and frozen permanently by checking them in along with the content.
+Ideally UUIDs for [[blog]] posts should be chosen when the post is created, and frozen permanently by checking them in along with the content.
Perhaps ikiwiki's blogging functionality could be hooked up to the [meta plugin](/meta/plugin/), with a new meta keyword (uuid? feed-uuid? atom-uuid?) to achieve this.
+
+> I've now knocked together a [[patch]], which is in the "force-uuids" branch of git://git.debian.org/git/users/smcv/ikiwiki.git (see also [gitweb](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=shortlog;h=refs/heads/force-uuids)).
+>
+> I'm not convinced that "uuid" is the best name for this functionality - the `<id>` in an Atom feed can be any URI, and one of the use-cases I have for this functionality in my own blog needs to have its `<id>` set to a URI that is not, in fact, its own address (it was a typo). "id" is a bit arrogant (forcing Atom terminology into a flat namespace!), "atom-id" is slightly misleading because it's also used for RSS... any ideas?
+>
+> While I was there, I noticed that the quality of the generated Atom/RSS feeds could be improved by making more use of the meta plugin if it's also enabled - would anyone object to me hacking on this some more?
+>
+> -[smcv](http://smcv.pseudorandom.co.uk/)
+
+> [[merged|done]], thank you!
+>
+> I chose to use the term guid, since it's both a generic term that fits
+> very well and describes both using a uuid and an url, and also happens
+> to be the term rss uses. ;-)
+>
+> Of course I'm happy if you can improve the feeds. They do already
+> use some meta information (author, copyright). --[[Joey]]
-[[tag wishlist]]
+[[!tag wishlist]]
An option to have absolute urls in wikilinks instead of relative ones would be useful,
for pages included into other pages out of the wiki rendering process (shtml for example)
-since these pages can be included from a subdir. Ditto, links from \[[ inline ..]] or \[[map ..]].
+since these pages can be included from a subdir. Ditto, links from \[[!inline ..]] or \[[!map ..]].
> You can make a wikilink absolute by prefixing it with a /, see
> [[ikiwiki/subpage/linkingrules/]]. Pagespecs match absolute by default. But what do
> change. --Ethan
>> I want the "last pages" in my sidebar. and some links to a few special pages.
->> \[[inline ]] or \\[[map ]] in the sidebar is a bad idea, (because each update rebuilds
+>> \[[!inline ]] or \\[[!map ]] in the sidebar is a bad idea, (because each update rebuilds
>> all the wiki), so I use server-side-include instead of the sidebar plugin;
>> this reduces the dependencies
>> my sidebar is generated as http://foo.org/menu/index.html, so all the links generated by
->> \[[inline ]] or \[[map ]] are relative to this position.
+>> \[[!inline ]] or \[[!map ]] are relative to this position.
>> Included from http://foo.org/section/sub/blah/index.shtml, the links are broken.
>>
>> — NicolasLimare
Conkeror...
--[[JasonBlevins]], March 22, 2008 10:35 EDT
+
+[[!tag wishlist]]
--- /dev/null
+The names are a bit backwards, but I guess inverting the sense of age would make people angry :-)
+
+I do not believe copy-and-paste of 3 lines is copyrightable, but in any case feel free to include in ikiwiki under the same terms.
+[[DavidBremner]]
+
+You can already do do sort=age reverse=yes [[done]] --[[Joey]]
+
+<pre>
+From 2fb2b561a678616bb0054a2d7a9d29df11998bc2 Mon Sep 17 00:00:00 2001
+From: David Bremner <bremner@pivot.cs.unb.ca>
+Date: Fri, 29 Aug 2008 15:05:41 -0300
+Subject: [PATCH] add sort='youth' to inline plugin
+
+---
+ IkiWiki/Plugin/inline.pm | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm
+index d2e5832..9e52712 100644
+--- a/IkiWiki/Plugin/inline.pm
++++ b/IkiWiki/Plugin/inline.pm
+@@ -194,6 +194,9 @@ sub preprocess_inline (@) {
+ elsif (! exists $params{sort} || $params{sort} eq 'age') {
+ @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
+ }
++ elsif (! exists $params{sort} || $params{sort} eq 'youth') {
++ @list=sort { $pagectime{$a} <=> $pagectime{$b} } @list;
++ }
+ else {
+ return sprintf(gettext("unknown sort type %s"), $params{sort});
+ }
+--
+1.5.6.3
+</pre>
> <http://jameswestby.net/scratch/create.diff>
> -- JamesWestby
+> For what it's worth, the following works:
+> `\[[!inline pages=!* rss=no atom=no postform=yes postformtext="Add a new page titled:"]]`
+> Add `rootpage=/` if you do this in `index.mdwn` to avoid creating subpages.
+> --[[JeremieKoenig]]
+
+
Maybe a very simple PHP frontend for serving the
statically generated pages, that would display a page editing form or
something like that for non-existent pages, wouldn't be too bad a thing
The aggregate plugin's handling of http 301 (moved permanently) could be
-improved. Per [[rfc 1945]]:
+improved. Per [[!rfc 1945]]:
> The requested resource has been assigned a new permanent URL
> and any future references to this resource should be done
How to transition to it though? inlines of aggregated content would need to
change their pagespecs to use `internal()`.
+
+> [[patch]] in git://git.debian.org/git/users/smcv/ikiwiki.git, branch "aggregate".
+> Migration is a two-step process: first change all your pagespecs to use `internal()`, then add `internalize="yes"` to all your aggregate invocations. --smcv.pseudorandom.co.uk
+
+> Thanks for working on this.
+>
+> I see one problem, if internalize is flipped on and there are existing
+> aggregated pages, htmlfn will not return the right filename for those
+> pages when expiring them. Seems that `$was_internal` (or just the full
+> source filename) should be recorded on a per-guid basis. Could you do
+> that?
+>
+> I'm weighing the added complexity of having an internalize option
+> (which people would have to add, and would probably forget), with just
+> making aggregate create all new pages as internal, and having a flag day
+> where all inlines and other uses of aggregated pages have to change
+> pagespecs to use `isinternal()`.
+>
+> There are real bugs that are fixed by making
+> aggregated plugins internal, including:
+> - Avoids web edits to aggregated pages. (Arguably a security hole;
+> though they can be locked..)
+> - Significant speed improvements.
+> - Less disk use.
+>
+> If internal has to be manually enabled, people will forget to. I'd rather
+> not have to worry about these bugs in the future. So, I'm thinking flag
+> day. --[[Joey]]
+
+> OK, there's a simpler approach in the same repository, branch
+> "aggregateinternal". It just adds an aggregateinternal option
+> for the whole wiki.
+>
+> On a flag day, everyone has to change their inline directives
+> to use `internal()`, after which this option can be switched on.
+> When changing the option, you'll have to clean up the mess from
+> old aggregated pages by hand, and re-aggregate.
+>
+> If this is a direction you prefer, the next step would be to
+> add support for existing wikis setting this option - for instance
+> it could look for non-internal pages that were previously
+> aggregated, and convert them to internal, the first time aggregation
+> runs. --smcv
+
+> Sure, that seems reasonable. Perhaps `ikiwiki-transition` could be used
+> to move the pages, and even, possibly update the pagespecs (not sure how
+> it could figure out which ones tho). --[[Joey]]
+
+> 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]]
-[[tag wishlist]]
+[[!tag wishlist]]
It would be cool if the CGI could be used to render dynamic pages. For instance, I might want to create a page with a `\[[map]]` according to a [[pagespec]] to be passed in the query string, instead of creating/hardcoding all possible pagespecs I might want to call.
> Nice idea, I'll try to find time to add a plugin doing this. --[[Joey]]
+>> [[done]] some time ago, as the [[plugins/404]] plugin --[[smcv]]
+
[[wishlist]]
--- /dev/null
+This patch allows disabling the backlinks in the config file by setting nobacklinks to 0.
+
+It is backwards compatible, and by default enables backlinks in the generated pages.
+
+<pre>
+--- IkiWiki/Render.pm.orig2 2009-01-06 14:54:01.000000000 +1300
++++ IkiWiki/Render.pm 2009-01-06 14:55:08.000000000 +1300
+@@ -107,7 +107,8 @@
+ $template->param(have_actions => 1);
+ }
+
+- my @backlinks=sort { $a->{page} cmp $b->{page} } backlinks($page);
++ my @backlinks=sort { $a->{page} cmp $b->{page} } backlinks($page)
++ unless defined $config{nobacklinks} && $config{nobacklinks} == 0;
+ my ($backlinks, $more_backlinks);
+ if (@backlinks <= $config{numbacklinks} || ! $config{numbacklinks}) {
+ $backlinks=\@backlinks;
+</pre>
> I agree that having this as an option is reasonable. Although it would
> take a fair amount of work. --[[Joey]]
-[[tag wishlist]]
+[[!tag wishlist]]
--- /dev/null
+[[!tag plugins/meta patch]]
+[[!template id=gitbranch branch=jon/defaultmeta author="[[Jon]]"]]
+
+I'd like to define [[plugins/meta]] values to apply across all pages
+site-wide unless the pages define their own: default values for meta
+definitions essentially.
+
+Here's a patch to achieve this (also in the "defaultmeta" branch of
+my github ikiwiki fork):
+
+ diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm
+ index b229592..3132257 100644
+ --- a/IkiWiki/Plugin/meta.pm
+ +++ b/IkiWiki/Plugin/meta.pm
+ @@ -13,6 +13,7 @@ sub import {
+ hook(type => "needsbuild", id => "meta", call => \&needsbuild);
+ hook(type => "preprocess", id => "meta", call => \&preprocess, scan => 1);
+ hook(type => "pagetemplate", id => "meta", call => \&pagetemplate);
+ + hook(type => "scan", id => "meta", call => \&scan);
+ }
+
+ sub getsetup () {
+ @@ -302,6 +303,15 @@ sub match {
+ }
+ }
+
+ +sub scan() {
+ + my %params = @_;
+ + my $page = $params{page};
+ + foreach my $type (map { s/^meta_//; $_ } grep /^meta_/, keys %config) {
+ + $pagestate{$page}{meta}{$type} = $config{"meta_$type"}
+ + unless defined $pagestate{$page}{meta}{$type};
+ + }
+ +}
+ +
+ package IkiWiki::PageSpec;
+
+ sub match_title ($$;@) {
+ diff --git a/doc/ikiwiki/directive/meta.mdwn b/doc/ikiwiki/directive/meta.mdwn
+ index 000f461..200c4b2 100644
+ --- a/doc/ikiwiki/directive/meta.mdwn
+ +++ b/doc/ikiwiki/directive/meta.mdwn
+ @@ -12,6 +12,12 @@ also specifies some additional sub-parameters.
+ The field values are treated as HTML entity-escaped text, so you can include
+ a quote in the text by writing `"` and so on.
+
+ +You can also define site-wide defaults for meta values by including them
+ +in your setup file, e.g.
+ +
+ + meta_copyright => "Copyright 2007 by Joey Hess",
+ + meta_license => "GPL v2+",
+ +
+ Supported fields:
+
+ * title
+
+-- [[Jon]]
+
+> This doesn't support multiple-argument meta directives like
+> `link=x rel=y`, or meta directives with special side-effects like
+> `updated`.
+>
+> The first could be solved (if you care) by a syntax like this:
+>
+> meta_defaults => [
+> { copyright => "© me" },
+> { link => "about:blank", rel => "silly", },
+> ]
+>
+> The second could perhaps be solved by invoking `meta::preprocess` from within
+> `scan` (which might be a simplification anyway), although this is complicated
+> by the fact that some (but not all!) meta headers are idempotent.
+>
+> --[[smcv]]
>> Mh.. well. I know this problem, too. I leave the Discussion sites open for no registrations, so that visitors can easily write a comment to this specific blog entry without the need for registration. (This would be the same behaviour, as many blogging engines are using). Maybe it is possible to wrote a plugin that would scan the text which is submitted via spamassassin or something similar. (Using this combined with known spam URLs would maybe reduce the load of the server if there are many webpages which are getting editted by someone). If you like this idea Joey I might be interested to write such a plugin after my exams this and the next month. :) -- [[Winnie]]
You might look at the Wikipedia page on "Spam\_in\_blogs" for more ideas. In particular, would it be possible to force a subset of the pages (by regex, but you'd choose the regex to match those pages which are publicly writable) to use rel="nofollow" in all links.
+
+> I just wanted to leave a link here to the [[todo/require_CAPTCHA_to_edit]] plugin patch. Unfortunately that plugin currently interacts badly with the openid plugin. -- [[Will]]
+
+
+---
+
+Ikiwiki now has a checkcontent hook that plugins can use to see content
+that is being entered and check it for spam/whatever.
+
+There is a blogspam plugin that uses the blogspam.org service
+to check for common spam signatures. --[[Joey]]
+
+[[done]]
--- /dev/null
+Apache's ErrorDocument directive lets you write a CGI script that will be invoked for all 404s.
+IkiWiki could offer one as an optional wrapper; it would do much the same thing that the
+existing recentchanges_link (or [[generic___39__do__61__goto__39___for_CGI]]) does when
+encountering a nonexistent page.
+
+I think it'd probably have to be a separate CGI script because the environment with which
+404 handlers are invoked is somewhat odd, and because it needs to return a 404 status
+(having said that, it might make sense for `recentchanges_link` to return 404 rather than
+200 anyway if the page doesn't exist).
+
+> This turns out to be untrue, as long as the wrapper lets a couple of extra
+> environment variables through. --[[smcv]]
+
+This would give IkiWiki the behaviour of many other wikis, where visiting a page that
+does not yet exist prompts you to create it, without having to invoke the CGI for
+successful requests.
+
+Due to [a well-known MSIE misfeature](http://support.microsoft.com/default.aspx?scid=kb;en-us;Q294807),
+error output needs to be at least 512 bytes long, so some padding might also be required.
+
+Implemented in the 'goto' branch in my git repository. You can see this
+feature in action [on my blog](http://smcv.pseudorandom.co.uk/no/such/page/).
+--[[smcv]]
+
+[[done]]
--- /dev/null
+[[!tag wishlist done]]
+
+[[!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
+==============
+
+Also see [[joey]]'s idea on [[users/xma/discussion]], to allow (filtered) anonymous push to this wiki's repository.
+
+> Ideally the filtering should apply the same constraints on what's pushed
+> as are applied to web edits. So locked pages can't be changed, etc.
+>
+> That could be accomplished by making the git pre-receive hook be a
+> ikiwiki wrapper. A new `git_receive_wrapper` config setting could cause
+> the wrapper to be generated, with `$config{receive}` set to true.
+>
+> When run that way, ikiwiki would call `rcs_receive`. In the case of git,
+> that would look at the received changes as fed into the hook on stdin,
+> and use `parse_diff_tree` to get a list of the files changed. Then it
+> could determine if the changes were allowed.
+>
+> To do that, it should first look at what unix user received the
+> commit. That could be mapped directly to an ikiwiki user. This would
+> typically be an unprivelidged user (that was set up just to allow
+> anonymous pushes), but you might also want to set up
+> separate users who have fewer limits on what they can push. And, of
+> course, pushes from the main user, who owns the wiki, would not be
+> checked at all. So, let's say `$config{usermap}` is a hash, something
+> like `{usera => "wikiusera", userb => "wikiuserb"}`, and pushes from
+> users not in the hash are not checked.
+>
+> Then it seems like it would want to call `check_canedit` to test if an
+> edit to each changed page is allowed. Might also want to call
+> `check_canattach` and `check_canremove` if the attach and remove plugins
+> are enabled. All three expect to be passed a CGI and a CGI::Session
+> object, which is a bit problimatic here. So dummy the objects up? (To call
+> `check_canattach` the changed attachment would need to be extracted to a
+> temp file for it to check..)
+>
+> If a change is disallowed, it would print out what was disallowed, and
+> exit nonzero. I think that git then discards the pushed objects (or maybe
+> they remain in the database until `git-gc` .. if so, that could be used
+> to DOS by uploading junk, so need to check this point).
+>
+> Also, I've not verified that the objects have been recieved already when
+> whe pre-receive hook is called. Although the docs seem to say that is the
+> case. --[[Joey]]
+
+>> Update: The git pre-receive hook stuff is written, and seems to work.
+>> I think it makes more sense than using diffs, and so think this todo
+>> could probably be closed.
+>> --[[Joey]]
+
+>>> I agree, closing this. I really prefer this solution to the one I was
+>>> initially proposing.
+>>> Is this pre-receive hook already enabled on ikiwiki.info?
+>>> If not, do you plan to enable it at some point?
+>>> --[[intrigeri]]
+
+>>>> [[news/git_push_to_this_wiki]] gave me the answer. Well done! --[[intrigeri]]
srcdir. This would allow the admin to review them, and manually
add/delete them before they bloat history.
-[[tag wishlist]]
+> I'd be inclined to implement that one by writing them to a nominated
+> underlay, I think, rather than having them in the srcdir but not in
+> the VCS. My [[plugins/contrib/album]] plugin could benefit from this
+> functionality, although in that case the photos should probably just
+> stay in the underlay forever (I already use an underlay on my own
+> websites for photos and software releases, which are too big to want
+> them in the VCS permanently.) --[[smcv]]
+
+[[!tag wishlist]]
-It would be great if I could tell ikiwiki to automatically instantiate pages for each tag, according to a template, especially when `$tagbase` is set.
+It would be great if I could tell ikiwiki to automatically instantiate pages for each [[tag|/tags]], according to a template, especially when `$tagbase` is set.
Tags are mainly specific to the object to which they’re stuck. However, I often use them the other way around, too: as concepts. And sometimes I’d like to see all pages related to a given concept (“tagged with a given tag”). The only way to do this with ikiwiki is to instantiate a page for each tag and slap a map on it. This is quite tedious and I’d really love to see Ikiwiki do so by default for all tags.
Also see: <http://madduck.net/blog/2008.01.06:new-blog/> and <http://users.itk.ppke.hu/~cstamas/code/ikiwiki/autocreatetagpage/>
-[[tag wishlist]]
+[[!tag wishlist plugins/tag patch]]
I would love to see this as well. -- dato
+
+---
+
+I have create a patch to [[tag.pm|plugins/tag]] for add the option for auto create tag pages.
+A new setting is used to enable or disable auto-create tag pages, `tag_autocreate`.
+The new tag file is created during the preprocess phase.
+The new tag file is then complied during the change phase.
+
+_tag.pm from version 3.01_
+
+
+ --- tag.pm 2009-02-06 10:26:03.000000000 -0700
+ +++ tag_new.pm 2009-02-06 12:17:19.000000000 -0700
+ @@ -14,6 +14,7 @@
+ hook(type => "preprocess", id => "tag", call => \&preprocess_tag, scan => 1);
+ hook(type => "preprocess", id => "taglink", call => \&preprocess_taglink, scan => 1);
+ hook(type => "pagetemplate", id => "tag", call => \&pagetemplate);
+ + hook(type => "change", id => "tag", call => \&change);
+ }
+
+ sub getopt () {
+ @@ -36,6 +37,36 @@
+ safe => 1,
+ rebuild => 1,
+ },
+ + tag_autocreate => {
+ + type => "boolean",
+ + example => 0,
+ + description => "Auto-create the new tag pages, uses autotagpage.tmpl ",
+ + safe => 1,
+ + rebulid => 1,
+ + },
+ +}
+ +
+ +my $autocreated_page = 0;
+ +
+ +sub gen_tag_page($) {
+ + my $tag=shift;
+ +
+ + my $tag_file=$tag.'.'.$config{default_pageext};
+ + return if (-f $config{srcdir}.$tag_file);
+ +
+ + my $template=template("autotagpage.tmpl");
+ + $template->param(tag => $tag);
+ + writefile($tag_file, $config{srcdir}, $template->output);
+ + $autocreated_page = 1;
+ +
+ + if ($config{rcs}) {
+ + IkiWiki::disable_commit_hook();
+ + IkiWiki::rcs_add($tag_file);
+ + IkiWiki::rcs_commit_staged(
+ + gettext("Automatic tag page generation"),
+ + undef, undef);
+ + IkiWiki::enable_commit_hook();
+ + }
+ }
+
+ sub tagpage ($) {
+ @@ -47,6 +78,10 @@
+ $tag=~y#/#/#s; # squash dups
+ }
+
+ + if (defined $config{tag_autocreate} && $config{tag_autocreate} ) {
+ + gen_tag_page($tag);
+ + }
+ +
+ return $tag;
+ }
+
+ @@ -125,4 +160,18 @@
+ }
+ }
+
+ +sub change(@) {
+ + return unless($autocreated_page);
+ + $autocreated_page = 0;
+ +
+ + # This refresh/saveindex is to complie the autocreated tag pages
+ + IkiWiki::refresh();
+ + IkiWiki::saveindex();
+ +
+ + # This refresh/saveindex is to fix the Tags link
+ + # With out this additional refresh/saveindex the tag link displays ?tag
+ + IkiWiki::refresh();
+ + IkiWiki::saveindex();
+ +}
+ +
+
+
+This uses a [[template|wikitemplates]] called `autotagpage.tmpl`, here is my template file:
+
+ \[[!inline pages="link(<TMPL_VAR TAG>)" archive="yes"]]
+
+
+A quirk I have not figured out is during the `sub change`, see my comments in the code.
+I am not sure if that is the best way to handle it.
+
+[[!tag patch]]
+-- Jeremy Schultz <jeremy.schultz@uleth.ca>
+
+No, this doesn't help:
+
+ + # This refresh/saveindex is to fix the Tags link
+ + # With out this additional refresh/saveindex the tag link displays ?tag
+ + IkiWiki::refresh();
+ + IkiWiki::saveindex();
+
+On the second extra pass, it doesn't notice that it has to update the "?"-link. If I run ikiwiki once more, it is updated. I don't know yet how this should be fixed, because I don't know the internals of ikiwiki well enough. Something inhibits detecting the need to update in refresh() in Render.pm; perhaps, this condition:
+
+ if (! $pagemtime{$page}) {
+ ...
+ push @add, $file;
+ ...
+ }
+
+is not satisfied for the newly created tag page. I shall put debug msgs into Render.pm to find out better how it works. --Ivan Z.
Together with the ability to have
[[wiki-formatted_comments|wiki-formatted_comments_with_syntax_plugin]],
-this would allow the use of ikiwiki for [[wikipedia literate programming]].
+this would allow the use of ikiwiki for [[!wikipedia literate programming]].
* I have started something along these lines see [[plugins/contrib/sourcehighlight]]. For some reason I started with source-highlight [[DavidBremner]]
* I wonder if this is similar to what you want: <http://iki.u32.net/setup/Highlight_Code_Plugin/>
+
+> The new [[plugins/highlight]] plugin is in ikiwiki core and supports
+> source code files natively. [[done]] --[[Joey]]
--- /dev/null
+Here is another [[patch]] for this. It is more up to date than either of the patches linked on the previous page. It is most similar to [[plugins/contrib/sourcehighlight]].
+
+Updated to use fix noted in [[bugs/multiple_pages_with_same_name]].
+
+-- [[Will]]
+
+----
+I was trying to replace sourcehighlight with sourcecode. I had to modify the
+htmlize call slightly so that it would work in a format directive.
+([modified version](http://pivot.cs.unb.ca/git/?p=ikiplugins.git;a=blob_plain;f=IkiWiki/Plugin/sourcecode.pm;hb=21fc57091edb9))
+
+> I haven't tested them, but those changes look sensible to me. -- [[Will]]
+
+I hit a wall the following example (the last commit in the above repo).
+
+ \[[!meta title="Solutions to assignment 1"]]
+
+ - [[!format cc """
+ test
+ """]]
+
+
+> I haven't actually tested this to see what the problem is. How does this fail?
+> Does source-highlight barf on the non-c++ content? Is there a wiki URL that shows the failure? -- [[Will]]
+>> Here is the content div from the output page
+>> [[DavidBremner]]
+
+ <div id="content">
+ <p><ul>
+ <li><div id="sourcecode"></li>
+ </ul>
+ 2beb4fd7289998159f61976143f66bb6</p>
+
+ <p></div></p>
+
+ </div>
+
+>>> That is quite strange. I tested your version of the plugin. I had to revert one your changes to get it to
+>>> work: the linenumber argument should not have a space at the end of it. Once I made that change,
+>>> everything worked as expected. The output I get for your example is below:
+
+ <div id="content">
+ <ul>
+ <li><div id="sourcecode"></li>
+ </ul>
+
+ <pre><tt><span class="linenum">00001:</span> <span class="normal">test</span></tt></pre>
+
+ <p></div></p>
+
+ </div>
+
+>>> I don't know what is going wrong for you... source-highlight, Markdown or something else.
+>>>> It's a well-known bug in old versions of markdown. --[[Joey]]
+>>> I do find it interesting the way the sourcecode `div` and the list get interleaved. That
+>>> just looks like a Markdown thing though.
+>>> In any case, I've updated the patch below to include most of your changes. -- [[Will]]
+
+----
+
+ #!/usr/bin/perl
+ # markup source files
+ # Originally by Will Uther
+ # With modifications by David Bremner
+ package IkiWiki::Plugin::sourcecode;
+
+ use warnings;
+ use strict;
+ use IkiWiki 2.00;
+ use open qw{:utf8 :std};
+
+ my %metaheaders;
+
+ sub import {
+ hook(type => "getsetup", id => "sourcecode", call => \&getsetup);
+ hook(type => "checkconfig", id => "sourcecode", call => \&checkconfig);
+ hook(type => "pagetemplate", id => "sourcecode", call => \&pagetemplate);
+ }
+
+ sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+ sourcecode_command => {
+ type => "string",
+ example => "/usr/bin/source-highlight",
+ description => "The command to execute to run source-highlight",
+ safe => 0,
+ rebuild => 1,
+ },
+ sourcecode_lang => {
+ type => "string",
+ example => "c,cpp,h,java",
+ description => "Comma separated list of suffixes to recognise as source code",
+ safe => 1,
+ rebuild => 1,
+ },
+ sourcecode_linenumbers => {
+ type => "boolean",
+ example => 1,
+ description => "Should we add line numbers to the source code",
+ safe => 1,
+ rebuild => 1,
+ },
+ sourcecode_css => {
+ type => "string",
+ example => "sourcecode_style",
+ description => "page to use as css file for source",
+ safe => 1,
+ rebuild => 1,
+ },
+ }
+
+ sub checkconfig () {
+ if (! $config{sourcecode_lang}) {
+ error("The sourcecode plugin requires a list of suffixes in the 'sourcecode_lang' config option");
+ }
+
+ if (! $config{sourcecode_command}) {
+ $config{sourcecode_command} = "source-highlight";
+ }
+
+ if (! length `which $config{sourcecode_command} 2>/dev/null`) {
+ error("The sourcecode plugin is unable to find the $config{sourcecode_command} command");
+ }
+
+ if (! $config{sourcecode_css}) {
+ $config{sourcecode_css} = "sourcecode_style";
+ }
+
+ if (! defined $config{sourcecode_linenumbers}) {
+ $config{sourcecode_linenumbers} = 1;
+ }
+
+ my %langs = ();
+
+ open(LANGS, "$config{sourcecode_command} --lang-list|");
+ while (<LANGS>) {
+ if ($_ =~ /(\w+) = .+\.lang/) {
+ $langs{$1} = 1;
+ }
+ }
+ close(LANGS);
+
+ foreach my $lang (split(/[, ]+/, $config{sourcecode_lang})) {
+ if ($langs{$lang}) {
+ hook(type => "htmlize", id => $lang, no_override=>1,
+ call => sub { htmlize(lang=>$lang, @_) },
+ keepextension => 1);
+ } else {
+ error("Your installation of source-highlight cannot handle sourcecode language $lang!");
+ }
+ }
+ }
+
+ sub htmlize (@) {
+ my %params=@_;
+
+ my $page = $params{page};
+
+ eval q{use FileHandle};
+ error($@) if $@;
+ eval q{use IPC::Open2};
+ error($@) if $@;
+
+ local(*SPS_IN, *SPS_OUT); # Create local handles
+
+ my @args;
+
+ if ($config{sourcecode_linenumbers}) {
+ push @args, '--line-number';
+ }
+
+ my $pid = open2(*SPS_IN, *SPS_OUT, $config{sourcecode_command},
+ '-s', $params{lang},
+ '-c', $config{sourcecode_css}, '--no-doc',
+ '-f', 'xhtml',
+ @args);
+
+ error("Unable to open $config{sourcecode_command}") unless $pid;
+
+ print SPS_OUT $params{content};
+ close SPS_OUT;
+
+ my @html = <SPS_IN>;
+ close SPS_IN;
+
+ waitpid $pid, 0;
+
+ my $stylesheet=bestlink($page, $config{sourcecode_css}.".css");
+ if (length $stylesheet) {
+ push @{$metaheaders{$page}}, '<link href="'.urlto($stylesheet, $page).'"'.
+ ' rel="stylesheet"'.
+ ' type="text/css" />';
+ }
+
+ return '<div id="sourcecode">'."\r\n".join("",@html)."\r\n</div>\r\n";
+ }
+
+ sub pagetemplate (@) {
+ my %params=@_;
+
+ my $page=$params{page};
+ my $template=$params{template};
+
+ if (exists $metaheaders{$page} && $template->query(name => "meta")) {
+ # avoid duplicate meta lines
+ my %seen;
+ $template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$metaheaders{$page}}));
+ }
+ }
+
+ 1
--- /dev/null
+[[!tag wishlist]]
+
+It would be nice if ikiwiki, particularly [[plugins/comments]]
+supported user avatar icons. I was considering adding a directive for this,
+as designed below.
+
+However, there is no *good* service for mapping openids to avatars --
+openavatar has many issues, including not supporting delegated openids, and
+after trying it, I don't trust it to push users toward.
+Perhaps instead ikiwiki could get the email address from the openid
+provider, though I think the perl openid modules don't support the openid
+2.x feature that allows that.
+
+At the moment, working on this doesn't feel like a good use of my time.
+--[[Joey]]
+
+Hmm.. unless is just always used a single provider (gravatar) and hashed
+the openid. Then wavatars could be used to get a unique avatar per openid
+at least. --[[Joey]]
+
+----
+
+The directive displays a small avatar image for a user. Pass it the
+email address, openid, or wiki username of the user.
+
+ \[[!avatar user@example.com]]
+ \[[!avatar http://joey.kitenet.net/]]
+ \[[!avatar user]]
+
+The avatars are provided by various sites. For email addresses, it uses a
+[gravatar](http://gravatar.com/). For openid,
+[openavatar](http://www.openvatar.com/) is used. For a wiki username, the
+user's email address is looked up and the gravatar for that user is
+displayed. (Of course, the user has to have filled in their email address
+on their Preferences page for that to work.)
+
+An optional second parameter can be included, containing additional
+options to pass in the
+[gravatar url](http://en.gravatar.com/site/implement/url).
+For example, this asks for a smaller gravatar, and if a user does
+not have a gravatar, uses a cute auto-generated "wavatar" avatar.
+
+ \[[!gravatar user@example.com "size=40&default=wavatar"]]
+
+The `gravitar_options` setting in the setup file can be used to
+specify additional options to pass. So for example if you want
+to use wavatars everywhere, set it to "default=wavatar".
--- /dev/null
+Problem: Suppose a server has 256 mb ram. Each ikiwiki process needs about
+15 mb, before it's loaded the index. (And maybe 25 after, but only one such
+process runs at any time). That allows for about 16 ikiwiki processes to
+run concurrently on a server, before it starts to swap. Of course, anything
+else that runs on the server and eats memory will affect this.
+
+One could just set `MaxClients 16` in the apache config, but then it's also
+limited to 16 clients serving static pages, which is silly. Also, 16 is
+optimistic -- 8 might be a saner choice. And then, what if something on the
+server decides to eat a lot of memory? Ikiwiki can again overflow memory
+and thrash.
+
+It occurred to me that the ikiwiki cgi wrapper could instead do locking of
+its own (say of `.ikiwiki/cgilock`). The wrapper only needs a few kb to
+run, and it starts *fast*. So hundreds could be running waiting for a lock
+with no ill effects. Crank `MaxClients` up to 256? No problem..
+
+And there's no real reason to allow more than one ikiwiki cgi to run at a
+time. Since almost all uses of the CGI lock the index, only one can really
+be doing anything at a time. --[[Joey]]
+
+[[done]]
--- /dev/null
+[[!tag patch patch/core]]
+[[!template id=gitbranch branch=smcv/ready/among author="[[smcv]]"]]
+
+IkiWiki::backlinks returns a form of $backlinks{$page} that has undergone a
+lossy transformation (to get it in the form that page templates want), making
+it more difficult to use in other contexts (like pagestats).
+
+A commit on my `among` branch splits it into IkiWiki::backlink_pages
+(which returns the keys of $backlinks{$page}, and might be suitable for
+exporting) and IkiWiki::backlinks (which calls backlink_pages, then performs
+the same lossy transformation as before on the result).
+
+[[done]] --[[Joey]]
users need to know to edit pages in the wiki. [[ikiwiki/Formatting]]
documents the basics, but doesn't include every preprocessor directive.
+> Thanks to Joey's work applying and fixing up my patches, this is mostly done.
+> The one thing I'd add above the way things currently work would be to add
+> the [[plugins/listdirectives]] plugin to [[plugins/goodstuff]].
+> Doing that requires making the decision about whether you really want the
+> documentation in every wiki - it is 200k. -- [[Will]]
+
+>> I don't think that it needs to be in goodstuff to close this, though I
+>> might decide to add it to goodstuff later. [[done]] --[[Joey]]
+
Note that there's a disctinction between being self-documenting for users,
and being complete documentation for ikiwiki. The basewiki is _not_
intended to be the latter, so it lacks the usage page, all the plugin
+use POSIX;
+use IkiWiki 2.00;
+
-+sub import { #{{{
++sub import {
+ hook(type => "checkconfig", id => "blogpost", call => \&checkconfig);
+ hook(type => "authcgi", id => "blogpost", call => \&authcgi);
+ hook(type => "canedit", id => "blogpost", call => \&canedit);
-+} # }}}
++}
+
-+sub checkconfig () { #{{{
++sub checkconfig () {
+ if (! defined $config{blogformat}){
+ $config{blogformat} = 'posts/%Y/%m/%d/$title';
+ }
+ if (! defined $config{blogusers}) {
+ $config{blogusers} = (); # disallow all posting by default
+ }
-+} #}}}
++}
+
-+sub authcgi ($$) { #{{{
++sub authcgi ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ $cgi->param("page", $page);
+ }
+
-+} #}}}
++}
+
-+sub blogpage ($) { #{{{
++sub blogpage ($) {
+ my $title=shift;
+ my $page=POSIX::strftime $config{blogformat}, localtime;
+ $page =~ s/\$title/$title/;
+ return $page;
-+} #}}}
++}
+
-+sub canedit ($$$) { #{{{
++sub canedit ($$$) {
+ my $page=shift;
+ my $cgi=shift;
+ my $session=shift;
+ return "" if ($config{blogusers} eq "*" ||
+ grep {$_ eq $user} $config{blogusers});
+ return ("not allowed to blog, $user");
-+} #}}}
++}
+
+1
Index: IkiWiki.pm
our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE
</pre>
-[[tag patch]]
+[[!tag patch patch/core]]
--- /dev/null
+The [[blogspam plugin|plugins/blogspam]] is just great.
+
+However, it lacks support in the web interface to [train comments as
+SPAM](http://blogspam.net/api/classifyComment.html), when they were
+erroneously identified as ham. It would be great to have such
+support, also in the spirit of helping
+[blogspam.net](http://blogspam.net) to get better and better.
+
+What would consist the most appropriate user interface is not entirely
+clear to me in the general case (wiki page editing). The case of blog
+comments look easier to: when the admin user is logged in (and if the
+blogspam plugin is enabled), each comment can have an extra link "mark
+as SPAM" which would both delete/revert the comment and submit it to
+the configured blogspam server for training.
+
+> Comments can't have an extra link when the admin user is logged
+> in, because the admin user sees the same static pages as everyone
+> else (non-admins still see the "remove" link provided by the remove
+> plugin, too). Perhaps a better UI would be that the action of that
+> link was overridden by the blogspam plugin to go to a form with
+> a checkbox for "also submit as spam"? --[[smcv]]
+
+Similarly, ham training can be plugged directly into the current
+comment moderation interface. Each comment that gets approved by the
+admin, can be sent to blogspam.net as ham. If this is considered too
+"aggressive", this behaviour can need to be explicitly enabled by
+turning on a configuration option.
+
+-- [[Zack]]
+
+[[!tag wishlist]]
return @ret;
}
- sub rcs_update () { #{{{
+ sub rcs_update () {
# Not needed.
- } #}}}
+ }
- sub rcs_prepedit ($) { #{{{
+ sub rcs_prepedit ($) {
return "";
- } #}}}
+ }
- sub rcs_commit ($$$;$$) { #{{{
+ sub rcs_commit ($$$;$$) {
my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
if (defined $user) {
system("bzr","whoami",$olduser);
return undef; # success
- } #}}}
+ }
- sub rcs_add ($) { # {{{
+ sub rcs_add ($) {
my ($file) = @_;
my @cmdline = ("bzr", "add", "--quiet", "$config{srcdir}/$file");
if (system(@cmdline) != 0) {
warn "'@cmdline' failed: $!";
}
- } #}}}
+ }
- sub rcs_recentchanges ($) { #{{{
+ sub rcs_recentchanges ($) {
my ($num) = @_;
eval q{use CGI 'escapeHTML'};
}
return @ret;
- } #}}}
+ }
- sub rcs_notify () { #{{{
+ sub rcs_notify () {
# TODO
- } #}}}
+ }
- sub rcs_getctime ($) { #{{{
+ sub rcs_getctime ($) {
# TODO
- } #}}}
+ }
1
I am serving notice that I am starting work on a calendar plugin inspired by Blosxom's calendar plugin. The current plan is to create a plugin that looks through all the source files matching a certain pagespec, and optionally spit out a month view for the specified month (default to current), or spit out a year view for a given year (defaulting to the current year), of a list of year with posts in them. The output would be a table, with the same CSS directives that the Blosxom plugin used to use (so that I can just reuse my css file). The links would be created to a $config{archivedir}/$year or $config{archivedir}/$year-$month file, which can just have
- \[[inline pages="blog/* and !*/Discussion and creation_year($year) and creation_month($month)" rss="no" atom="no" show="0"]]
+ \[[!inline pages="blog/* and !*/Discussion and creation_year($year) and creation_month($month)" rss="no" atom="no" show="0"]]
or some thing to generate a archive of postings.
This plugin is inspired by the calendar plugin for Blosxom, but derivesno code from it. This plugin is essentially a fancy front end to archives of previous pages, usually used for blogs. It can produce a calendar for a given month, or a list of months for a given year. To invoke the calendar, just use the preprocessor directive:
- \[[calendar ]]
+ \[[!calendar ]]
or
- \[[calendar type="month" pages="blog/* and !*/Discussion"]]
+ \[[!calendar type="month" pages="blog/* and !*/Discussion"]]
or
- \[[calendar type="year" year="2005" pages="blog/* and !*/Discussion"]]
+ \[[!calendar type="year" year="2005" pages="blog/* and !*/Discussion"]]
The year and month entities in the out put have links to archive index pages, which are supposed to exist already. The idea is to create an archives hierarchy, rooted in the subdirectory specified in the site-wide customization variable, archivebase. archivebase defaults to "archives". Links are created to pages "$archivebase/$year" and "$archivebase/$year/$month". The idea is to create annual and monthly indices, for example, by using something like this sample from my archives/2006/01.mdwn
- \[[meta title="Archives for 2006/01"]]
- \[[inline rootpage="blog" atom="no" rss="no" show="0" pages="blog/* and !*/Discussion and creation_year(2006) and creation_month(01)" ]]
+ \[[!meta title="Archives for 2006/01"]]
+ \[[!inline rootpage="blog" atom="no" rss="no" show="0" pages="blog/* and !*/Discussion and creation_year(2006) and creation_month(01)" ]]
I'll send in the patch via email.
> > I'm sending in an updated package, and have removed the older version you had here.--ManojSrivastava
-[[tag patch]]
+[[!tag patch]]
----
>> wouldn't embed the feed link into `<head>` so that browsers can automatically
>> find it.
-[[tag wishlist]]
+[[!tag wishlist]]
--- /dev/null
+[[!tag patch wishlist]]
+
+ikiwiki should support [Central Authentication
+Service](http://www.ja-sig.org/products/cas/) authentication in order to use
+this <acronym title='Single Sign On'>SSO</acronym> mechanism very popular in
+universities web services.
+
+I have already written a first draft plugin supporting that authentication
+mechanism. It works for me with my university CAS service. I did not try it
+with other CAS server but it do not see any reason why it should not work.
+
+What is the best way to submit it to you (just in case it can help my patch
+follows) ?
+
+--[[/users/bbb]]
+
+> Inline here is ok; git-am by mail is ok; a git repo I can pull from also
+> ok.
+>
+> This looks pretty acceptable as-is, but you need to put a copyright and
+> license statement at the top. I have a few questions that I'll insert
+> inline with the patch below. --[[Joey]]
+
+------------------------------------------------------------------------------
+ diff --git a/IkiWiki/Plugin/cas.pm b/IkiWiki/Plugin/cas.pm
+ new file mode 100644
+ index 0000000..ea189df
+ --- /dev/null
+ +++ b/IkiWiki/Plugin/cas.pm
+ @@ -0,0 +1,94 @@
+ +#!/usr/bin/perl
+ +# JaSIG CAS support by Bruno Beaufils <bruno@boulgour.com>
+ +package IkiWiki::Plugin::cas;
+ +
+ +use warnings;
+ +use strict;
+ +use IkiWiki 2.00;
+ +use AuthCAS; # http://search.cpan.org/~osalaun/AuthCAS-1.3.1/
+
+> In ikiwiki we generally deman-load perl modules only when they're used.
+> This avoids loading expensive modules when the CGI isn't doing
+> authentication. Can you do that with AuthCAS? Something like this before
+> the use of it: `eval q{use AuthCAS}; error $@ if $@`
+
+ +
+ +sub import {
+ + hook(type => "getopt", id => "cas", call => \&getopt);
+ + hook(type => "auth", id => "cas", call => \&auth);
+ + hook(type => "formbuilder_setup", id => "cas", call => \&formbuilder_setup);
+ +}
+
+> Could you please use tabs for indentation of program flow?
+
+ +# FIXME: We should check_config to ensure that :
+ +# * cas_url and ca_file are present
+
+> Please fix that..
+
+ +# * no other auth plugin are present (at least passwordauth and openid)
+
+> Why would you want to make other auth plugins not work? Could a site not
+> legitimatly chose to use this and another auth method?
+
+ +sub getopt () {
+ + eval q{use Getopt::Long};
+ + error($@) if $@;
+ + Getopt::Long::Configure('pass_through');
+ + GetOptions("cas_url=s" => \$config{cas_url});
+ + GetOptions("ca_file=s" => \$config{ca_file});
+ +}
+ +
+ +sub auth ($$) {
+ + my $q=shift;
+ + my $session=shift;
+ +
+ + my $cas = new AuthCAS(casUrl => $config{'cas'}{'cas_url'},
+ + CAFile => $config{'cas'}{'ca_file'});
+ +
+ + my $service = $config{'cgiurl'};
+ + my $ticket = $q->param('ticket');
+ +
+ + unless (defined($ticket)) {
+ + $service .= "?$ENV{QUERY_STRING}";
+ + my $login_url = $cas->getServerLoginURL($service);
+ + debug("CAS: asking a Service Ticket for service $service");
+ + IkiWiki::redirect($q, $login_url);
+ + exit 0;
+ + } else {
+ + $service = $service . "?$ENV{QUERY_STRING}";
+ + $service =~ s/\&ticket=$ticket//;
+ + my $user = $cas->validateST($service, $ticket);
+ + if (defined $user) {
+ + debug("CAS: validating a Service Ticket ($ticket) for service $service");
+ + $session->param(name=>$user);
+ + $session->param(CASservice=>$service);
+ + IkiWiki::cgi_savesession($session);
+ + } else {
+ + error("CAS failure: ".&AuthCAS::get_errors());
+ + }
+ + }
+ +}
+ +
+ +# I use formbuilder_setup and not formbuilder type in order to bypass the
+ +# Logout processing done in IkiWiki::CGI::cgi_prefs()
+ +sub formbuilder_setup (@) {
+ + my %params=@_;
+ +
+ + my $form=$params{form};
+ + my $session=$params{session};
+ + my $cgi=$params{cgi};
+ + my $buttons=$params{buttons};
+ +
+ + my $cas = new AuthCAS(casUrl => $config{'cas'}{'cas_url'},
+ + CAFile => $config{'cas'}{'ca_file'});
+ +
+ + if ($form->title eq "preferences") {
+ + # Show the login
+ + if (! defined $form->field(name => "name")) {
+ + $form->field(name => "CAS ID",
+ + disabled => 1,
+ + value => $session->param("name"),
+ + size => 50,
+ + force => 1,
+ + fieldset => "login");
+ + }
+ +
+ + # Force a logout if asked
+ + if ($form->submitted && $form->submitted eq 'Logout')
+ + {
+ + debug("CAS: asking to remove the Ticket Grant Cookie");
+ + IkiWiki::redirect($cgi, $cas->getServerLogoutURL($config{'url'}));
+ + $session->delete();
+ + exit 0;
+ + }
+ + }
+ +}
+ +
+ +1
+ diff --git a/doc/plugins/cas.mdwn b/doc/plugins/cas.mdwn
+ new file mode 100644
+ index 0000000..2f2f53e
+ --- /dev/null
+ +++ b/doc/plugins/cas.mdwn
+ @@ -0,0 +1,18 @@
+ +[[ template id=plugin name=cas core=0 author="[[bbb]]"]]
+ +[[ tag type/auth]]
+ +
+ +This plugin allows users to use authentication offered by a
+ +[JaSIG](http://www.ja-sig.org) [<acronym title='Central Authentication
+ +Service'>CAS</acronym>](http://www.ja-sig.org/products/cas/) server to log
+ +into the wiki.
+ +
+ +The plugin needs the [[!cpan AuthCAS-1.3.1]] perl module.
+
+> Does it really need that specific version? I think you should lose the
+> version part.
+
+ +
+ +This plugin has two mandatory configuration option. You **must** set `--cas_url`
+ +to the url of a server offering CAS 2.0 authentication. You must also set the
+ +`--ca_file` to an absolute path to the file containing CA certificates used by
+ +the server (generally, aka under Debian, fixing that value to
+ +`/etc/ssl/certs/ca-certificates.crt` is sufficient).
+
+> It would be good to add commented-out examples of these to
+> ikiwiki.setup as well.
+
+ +This plugin is not enabled by default. It can not be used with other
+ +authentication plugin, such as [[passwordauth]] or [[openid]].
+
+------------------------------------------------------------------------------
--- /dev/null
+Would it make sense to automatically delete a page if it's edited and
+cleared to be entirely empty (or only have whitespace)? Discuss. --[[Joey]]
+
+ I'd say so; yes. A method of deleting pages via the web would be great; I
+can't think of a use of keeping blank pages around. What about vandalism --
+if someone blanks a page and deletes it and someone else wishes to restore
+it; or is undoing edits via the web a bigger issue? -- [[users/Jon]]
+
+Of course there's already a way to delete pages (remove plugin). So the
+question is really:
+
+* Does it make sense to have a second way to do it, by clearing the page?
+* Should it be enabled even if the full remove plugin isn't?
+
+Re vandalism in general, I am generally happy using git-revert to kill the
+offending change. --[[Joey]]
+
+I don't think we need a second way to delete pages, which would probably be
+used by the only few people who will learn it's possible by random
+documentation reading, find it useful, *and* remember it. -- [[intrigeri]]
+
+On the other hand, clearing the page's whole content essentially means deleting
+the page. That's what the user intended to do in this case. The information
+content of an empty vs. a deleted page is essentially the same, I'd say. But
+having ikiwiki remove those stale pages would save some (minimal, admittedly)
+time needed for manual clean-up. --[[tschwinge]]
+
+On EmacsWiki, a page is marked for deletion when it contains just the DeletedPage
+keyword and if there were no page editions since XX days. Here, I use pages that
+can be empty everyday and filled all day long. It does not make sense to me to
+delete these pages :). --[[xma]]
+
+I was not aware of [[plugins/remove]]. I don't think another method is necessary -- [[users/Jon]]
> recognise such commit messages when parsing the logs. Do that and extend
> to the other modules and I'll accept it. --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
<pre>
--- IkiWiki/Rcs/svn.pm (revision 2650)
--- /dev/null
+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 was thinking one would be foreground, the other background. Don't
+>>> know if setting the background makes sense or not.
+
+>> 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]]
+
+>> Yes, it's a good intro plugin, have at it! --[[Joey]]
+
+---
+
+This is a RC1 of my `color` plugin. It works for me well, but all your
+comments are very welcome. --[[Paweł|ptecza]]
+
+> Sure, I have a couple.
+
+>> Great! Thank you very much! --[[Paweł|ptecza]]
+
+> The preprocess function is passed named parameters. The hack you have of
+> hardcoding use of `$_[0]` and `$_[2]` can fail at any time.
+
+>> But the problem is that arguments of my plugin don't have a name.
+>> How can I identify them in `params` hash?
+
+>> Similar hardcoded method I've found in `img` plugin :) But only one
+>> argument is not named there (image path).
+
+>>> I think I hadn't realized what you were doing there. The order
+>>> for unnamed parameters can in fact be relied on.
+>>>
+>>> --[[Joey]]
+
+>> Maybe I shouldn't use so simple plugin syntax? For following syntax
+>> I wouldn't have that problem:
+
+>> \[[!color fg=white bg=red text="White text on red background"]]
+
+> `replace_preserved_style` is passed a single parameter, so its prototype
+> should be `($)`, not `(@)`. Ditt `preserve_style`, it should have
+> `($$)`.
+
+>> OK, it will be fixed.
+
+> The sanitize hook is always passed `$params{content}`, so there should be
+> no reason to check that it exists. Also, it shouldn't be done in a
+> sanitize hook, since html sanitization could run _after_ that santize
+> hook. It should use a format hook.
+
+>> Probably you're right. It was rather paranoid checking ;) Thanks for
+>> the hook hint!
+
+> The preprocess hook needs to call `IkiWiki::preprocess` on the content
+> passed into it if you want to support nesting other preprocessor
+> directives inside the color directive. See `preprocess_toggleable` in the
+> toggle plugin, for example.
+>
+> I'm not a big fan of the dummy text `COLORS { ... } SROLOC;TEXT { ... TXET }`
+> The method used by toggle of using two real `<div>`s seems slightly
+> better. --[[Joey]]
+
+>> I don't like that too, but I didn't have better idea :) Thank you for
+>> the hint! I'll take a look at `toggle` plugin.
+
+---
+
+And here is RC2 of that plugin. I've changed a plugin syntax, because the old
+seems to be too enigmatic and it was hard to me to handle unnamed parameters
+in not hardcoded way. I hope that my changes are acceptable for you.
+Of course, I'm open for discussion or exchange of ideas :) --[[Paweł|ptecza]]
+
+> One question, why the 2px padding for span.color? --[[Joey]]
+
+>> Sorry for a long silence, but I had Internet free summer holiday :)
+>> I did that, because backgrounded text without any padding looks
+>> strange for me ;) You can remove it if you don't like that padding.
+>> --[[Paweł|ptecza]]
+
+>>> Joey, will you add that plugin to Ikiwiki 2.61? :) --[[Paweł|ptecza]]
+
+>>>> I also had a long net-free summer holiday. :-) The [[patch]] is
+>>>> ready for integration (made a few minor changes). Is this GPL 2?
+>>>> --[[Joey]]
+
+>>>>> No problem. I guessed it, because I've not seen your commits
+>>>>> at [[RecentChanges]] page in last days and I subscribe your
+>>>>> [blog](http://kitenet.net/~joey/blog/entry/vacation/) :D
+>>>>> It's GPL-2+ like your Ikiwiki and the most external plugins.
+>>>>> --[[Paweł|ptecza]]
+
+ --- /dev/null 2008-06-21 02:02:15.000000000 +0200
+ +++ color.pm 2008-07-27 14:58:12.000000000 +0200
+ @@ -0,0 +1,69 @@
+ +#!/usr/bin/perl
+ +# Ikiwiki text colouring plugin
+ +# Paweł‚ Tęcza <ptecza@net.icm.edu.pl>
+ +package IkiWiki::Plugin::color;
+ +
+ +use warnings;
+ +use strict;
+ +use IkiWiki 2.00;
+ +
+ +sub import {
+ + hook(type => "preprocess", id => "color", call => \&preprocess);
+ + hook(type => "format", id => "color", call => \&format);
+ +}
+ +
+ +sub preserve_style ($$$) {
+ + my $foreground = shift;
+ + my $background = shift;
+ + my $text = shift;
+ +
+ + $foreground = defined $foreground ? lc($foreground) : '';
+ + $background = defined $background ? lc($background) : '';
+ + $text = '' unless (defined $text);
+ +
+ + # Validate colors. Only color name or color code are valid.
+ + $foreground = '' unless ($foreground &&
+ + ($foreground =~ /^[a-z]+$/ || $foreground =~ /^#[0-9a-f]{3,6}$/));
+ + $background = '' unless ($background &&
+ + ($background =~ /^[a-z]+$/ || $background =~ /^#[0-9a-f]{3,6}$/));
+ +
+ + my $preserved = '';
+ + $preserved .= '<span class="color">';
+ + $preserved .= 'color: '.$foreground if ($foreground);
+ + $preserved .= '; ' if ($foreground && $background);
+ + $preserved .= 'background-color: '.$background if ($background);
+ + $preserved .= '</span>';
+ + $preserved .= '<span class="colorend">'.$text.'</span>';
+ +
+ + return $preserved;
+ +
+ +}
+ +
+ +sub replace_preserved_style ($) {
+ + my $content = shift;
+ +
+ + $content =~ s!<span class="color">((color: ([a-z]+|\#[0-9a-f]{3,6})?)?((; )?(background-color: ([a-z]+|\#[0-9a-f]{3,6})?)?)?)</span>!<span class="color" style="$1">!g;
+ + $content =~ s!<span class="colorend">!!g;
+ +
+ + return $content;
+ +}
+ +
+ +sub preprocess (@) {
+ + my %params = @_;
+ +
+ + # Preprocess the text to expand any preprocessor directives
+ + # embedded inside it.
+ + $params{text} = IkiWiki::preprocess($params{page}, $params{destpage},
+ + IkiWiki::filter($params{page}, $params{destpage}, $params{text}));
+ +
+ + return preserve_style($params{foreground}, $params{background}, $params{text});
+ +}
+ +
+ +sub format (@) {
+ + my %params = @_;
+ +
+ + $params{content} = replace_preserved_style($params{content});
+ + return $params{content};
+ +}
+ +
+ +1
+ --- /dev/null 2008-06-21 02:02:15.000000000 +0200
+ +++ color.mdwn 2008-07-27 15:04:42.000000000 +0200
+ @@ -0,0 +1,25 @@
+ +\[[!template id=plugin name=color core=0 author="[[ptecza]]"]]
+ +
+ +This plugin can be used to color a piece of text on a page.
+ +It can be used to set the foreground and/or background color of the text.
+ +
+ +You can use a color name (e.g. `white`) or HTML code (e.g. `#ffffff`)
+ +to define colors.
+ +
+ +Below are a few examples:
+ +
+ + \[[!color foreground=white background=#ff0000 text="White text on red background"]]
+ +
+ +In the above example, the foreground color is defined as a word, while the background color is defined as a HTML
+ +color code.
+ +
+ + \[[!color foreground=white text="White text on default color background"]]
+ +
+ +The background color is missing, so the text is displayed on default background.
+ +
+ + \[[!color background=#ff0000 text="Default color text on red background"]]
+ +
+ +The foreground is missing, so the text has the default foreground color.
+ --- style.css-orig 2008-07-27 15:12:39.000000000 +0200
+ +++ style.css 2008-07-27 15:15:06.000000000 +0200
+ @@ -333,3 +333,7 @@
+ background: #eee;
+ color: black !important;
+ }
+ +
+ +span.color {
+ + padding: 2px;
+ +}
+
+[[done]]
I would like to allow comments on ikiwiki pages without CGI.
-I have in mind something like
- * Use a pagetemplate hook
- in a plugin (DONE)
- * add a mailto: url to each page matching some pagespec
- (currently every page gets a comment footer)
- * this mailto url goes to an address identifying the page (something like
- user-iki-FE653b@host.fqdn.tld). (DONE)
- > I wonder if it would be more or less natural to put an encoded form
- > of the page name in the email address? I'm thinking about something
- > like `wikiname+index@host` or `wikiname+todo+comment_by_mail@host`.
- > The basic transformation would be to call `titlepage($page)` (in the
- > C locale), followed by replacing "/" with "+" (since "/" is not
- > valid in mails). --[[Joey]]
- >> I guess you are right, there is no point being more obscure
- >> than necessary. I am leaning towards [something](http://www.cs.unb.ca/~bremner/blog/posts/encoding) not
- >> calling titlepage but in the same spirit. --[[DavidBremner]]
-
- * on the mail receiving end, these messages are either deleted, or ran through
- a filter to be turned into blog posts.
-
- - I'm thinking about how the filter should work. Within a
- mail client, or as a batch tool to scan a mailbox? How to interact with version control, if at all?
-
- * the same plugin can check for comments on a particular page next time the wiki
- is generated, and add a link. (more or less done)
- > If the filter just checks in the posts into revision control, the
- > post-commit hook would handle updating the wiki to include those
- > posts as they come in. --[[Joey]]
- * work in progress can be
-
- - [cloned](http://pivot.cs.unb.ca/git/ikiperl.git), or
- - [browsed](http://pivot.cs.unb.ca/git/?p=ikipostal.git;a=summary)
-
-
-Any comments? Write them here or send them to [[DavidBremner]]
-
-> I don't want to derail this with too much blue-skying, but I was thinking
-> earlier that it would be nice if ikiwiki could do something sensible with
-> mailbox files, such as turning them into a (threaded?) blog display.
->
-> One reason I was thinking about that was just that it would be nice to
-> be able to use ikiwiki for mailing list archives. But another reason was
-> that it would be nice to solve the problem described in
-> [[discussion_page_as_blog]]. For that you really want a threaded system,
-> and mailbox file formats already have threading.
->
-> If that were done, it would tie into what you're working on in an
-> interesting way, since the incoming mail would only need to be committed to
-> the appropriate mailbox file, with ikiwiki then running to process it.
-> --[[Joey]]
->> It is an interesting idea. I like that it uses an arbitrary MUA
->> as a "moderation" interface. One thing it made me think about is
->> how to encode reference (threading) information. One can of
->> course encode this into local-part, but I wonder if it would be
->> better to use header features of mailto (this could also be an
->> alternative to tagged mail addresses for page references).
->> Various client handling of mailto always seemed a bit fragile to
->> me but maybe I am just behind the times. Most headers are ignored, but
->> pseudo-headers in the body might work. For example:
->>[test](mailto:bremner@somewhere.ca?body=X-Iki-Page:%20test%0AX-Iki-thread:%20foobar). I hesitate to use the subject because every mail admin in the
->> world seems to want to add things to the front of it.
->> -- [[DavidBremner]]
->>> Although it is in python, just from reading the Debian ITP, it
->>> looks like
->>> [mnemosyne-blog](http://www.red-bean.com/~decklin/mnemosyne/)
->>> might be an interesting backend to use or at least steal ideas
->>> from :-) --[[David Bremner]]
+> [[done]], see [[plugins/contrib/postal]]
--- /dev/null
+I am moving some of the "settled" discussion here, I hope that is
+appropriate. --[[DavidBremner]]
+
+ > I wonder if it would be more or less natural to put an encoded form
+ > of the page name in the email address? I'm thinking about something
+ > like `wikiname+index@host` or `wikiname+todo+comment_by_mail@host`.
+ > The basic transformation would be to call `titlepage($page)` (in the
+ > C locale), followed by replacing "/" with "+" (since "/" is not
+ > valid in mails). --[[Joey]]
+ >> I guess you are right, there is no point being more obscure
+ >> than necessary. I am leaning towards [something](http://www.cs.unb.ca/~bremner/blog/posts/encoding) not
+ >> calling titlepage but in the same spirit. --[[DavidBremner]]
+
+In response to the suggestion by Joey to process mailboxes into blogs
+>> One thing it made me think about is
+>> how to encode reference (threading) information. One can of
+>> course encode this into local-part, but I wonder if it would be
+>> better to use header features of mailto (this could also be an
+>> alternative to tagged mail addresses for page references).
+>> Various client handling of mailto always seemed a bit fragile to
+>> me but maybe I am just behind the times. Most headers are ignored, but
+>> pseudo-headers in the body might work. For example:
+>>[test](mailto:bremner@somewhere.ca?body=X-Iki-Page:%20test%0AX-Iki-thread:%20foobar). I hesitate to use the subject because every mail admin in the
+>> world seems to want to add things to the front of it.
+>> -- [[DavidBremner]]
--- /dev/null
+# Known issues with the [[plugins/comments]] plugin
+
+## Unimplemented
+
+* Instead of just a link to add a comment, it could have a form to enter
+ the title, similar to the form for adding a new blog post.
+
+ > I'm not sure this is so useful? On Livejournal titles are allowed on
+ > comments, but very rarely used (and indeed usually not very useful);
+ > it's hard enough to get some people to title their blog posts :-)
+ > --[[smcv]]
+
+## Won't fix
+
+* Because IkiWiki generates static HTML, we can't have a form inlined in
+ page.tmpl where the user fills in an entire comment and can submit it in
+ a single button-press, without being vulnerable to cross-site request forgery.
+ So I'll put this in as wontfix. --[[smcv]]
+
+ > Surely there's a way around that?
+ > A web 2.0 way comes to mind: The user clicks on a link
+ > to open the comment post form. While the nasty web 2.0 javascript :)
+ > is manipulating the page to add the form to it, it looks at the cookie
+ > and uses that to insert a sid field.
+ >
+ > Or, it could have a mandatory preview page and do the CSRF check then.
+ > --[[Joey]]
+
+* It would be useful to have a pagespec that always matches all comments on
+ pages matching a glob. Something like `comment(blog/*)`.
+ Perhaps postcomment could also be folded into this? Then the pagespec
+ would match both existing comments, as well as new comments that are
+ being posted.
+
+ > Please see [[plugins/comments/discussion]]. If I've convinced you that
+ > internal pages are the way forward, then sure, we can do that, because
+ > people who can comment still won't be able to edit others' comments
+ > (one of my goals is that commenters can't put words into each other's
+ > mouths :-) )
+ >
+ > On the other hand, if you still want me to switch this plugin to "real"
+ > pages, or if internal pages might become editable in future, then
+ > configuring lockedit/anonok so a user X can add comments to blog pages
+ > would also let X edit/delete comments on blog pages (including those
+ > written by others) in arbitrary ways, which doesn't seem good. --[[smcv]]
+
+ > I had a look at implementing comment() and fell afoul of
+ > some optimisations that assume only internal() will be used to match
+ > internal pages. So probably this isn't worth doing. --[[Joey]]
+
+## Done
+
+* There is some common code cargo-culted from other plugins (notably inline and editpage) which
+ should probably be shared
+
+ > Actually, there's less of this now than there used to be - a lot of simple
+ > things that were shared have become unshareable as they became more
+ > complex. --[[smcv]]
+
+ > There's still goto. You have a branch for that. --[[Joey]]
+
+ >> Now merged --[[smcv]]
+
+* The default template should have a (?) icon next to unauthenticated users (with the IP address
+ as title) and an OpenID icon next to OpenIDs
+
+ > Done in my comments git branch, at least as a mockup (using the (?),
+ > {x} and {*} smileys for anonymous, OpenID and login respectively).
+ > --[[smcv]]
+
+ >> I've improved this to use independent icons from the wikiicons
+ >> directory (untested!) --[[smcv]]
+
+ >>> The new code produces links like /wikiisons/openid.png, which
+ >>> fail if ikiwiki is not at the root of the web server. --[[Joey]]
+
+ >>>> Sorry, I should have spotted that (the assumption failed on my demo
+ >>>> site, but the push to that site was when I was on the way out, so I
+ >>>> didn't have time to investigate). As a note for other ikiwiki hackers,
+ >>>> I should have used
+ >>>> `<img src="<TMPL_VAR NAME=BASEURL>wikiicons/openid.png" />`. --[[smcv]]
+
+ >>> I got to wondering if the icons are needed. On my comments branch
+ >>> (not master), I've dropped the icons and info can be seen by hovering
+ >>> over the author's name. Idea being that you probably don't care how
+ >>> they authenticated unless something is weird, and in that case you
+ >>> can hover to check. Does that make sense, should I merge it?
+ >>> --[[Joey]]
+
+ >>>> Yeah, go ahead. I preferred my layout with the author before the
+ >>>> comment - perhaps that's Livejournal's influence :-) - but I can always
+ >>>> edit the templates for my own site. As long as the default is something
+ >>>> reasonable and both layouts are possible, I don't really mind.
+ >>>> Minimizing the number of "resource" files in the basewiki also seems
+ >>>> a good goal. --[[smcv]]
+
+* Previews always say "unknown IP address"
+
+ > Fixed in my comments branch by commits bc66a00b and 95b3bbbf --[[smcv]]
+
+* The Comments link in the "toolbar" is to `index.html#comments`, not the
+ desired `./#comments`
+
+ > Fixed in my comments branch by commit 0844bd0b; commits 5b1cf21a
+ > and c42f174e fix another `beautify_urlpath` bug and add a regression test
+ > --[[smcv]]
+
+
+* Now that inline has some comments-specific functionality anyway, it would
+ be good to output `<link rel="comments">` in Atom and the equivalent in RSS.
+
+ > Fixed in my comments branch by d0d598e4, 3feebe31, 9e5f504e --[[smcv]]
+
+
+* Add `COMMENTOPENID`: the authenticated/verified user name, if and only if it was an OpenID
+
+ > Done in my comments git branch --[[smcv]]
+
+ > Not seeing it there, which branch? --[[Joey]]
+
+ >> Bah, git push --all is not the default... 'comments' branch now (I've also rebased it).
+ >> Sorry, I'm on mobile Internet at the moment... --[[smcv]]
+
+ >>> merged by [[Joey]] in commit 0f03af38 --[[smcv]]
+
+* Should the comments be visually set off more from the page above?
+ Rather than just a horizontal rule, I'm thinking put the comments
+ in a box like is used for inlined pages.
+
+ > I did put them in a box in the CSS... I agree the default template
+ > could do with visual improvement though. --[[smcv]]
+
+ >> I'll consider this solved by [[Joey]]'s changes. --[[smcv]]
+
+* One can use inline to set up a feed of all comments posted to any page.
+ Using template=comment they are displayed right. Only problem
+ is there is no indication in that template of what page each comment in the
+ feed is a comment on. So, if a comment is inlined into a different page,
+ I think it should show a link back to the page commented on.
+ (BTW, the rss feed in this situation seems ok; there the link element
+ points back to the parent page.
+
+ > done --[[Joey]]
+
+* One of Joey's commit messages says "Not ideal, it would be nicer to jump to
+ the actual comment posted, but no anchor is available". In fact there is
+ an anchor - the `\[[_comment]]` preprocessing wraps the comment in a `<div>`
+ with id="comment_123" or something. I'll fix this, unless Joey gets there
+ first. --[[smcv]]
+
+ > done --[[Joey]]
+
+* If a spammer posts a comment, it is either impossible or hard to clean
+ up via the web. Would be nice to have some kind of link on the comment
+ that allows trusted users to remove it (using the remove plugin of
+ course).
+
+ > Won't the remove plugin refuse to remove internal pages? This would be
+ > a good feature to have, though. --[[smcv]]
+
+ > Here, FWIW, is the first ikiwiki comment spam I've seen:
+ > <http://waldeneffect.org/blog/Snake_bite_information/#blog/Snake_bite_information/comment_1>
+ > So that took about 10 days...
+ > --[[Joey]]
+
+ >> Implemented in my 'comments' branch, please review. It turns out
+ >> [[plugins/remove]] is happy to remove internal pages, so it was quite
+ >> easy to do. --[[smcv]]
+
+ >>> done --[[Joey]]
I'd like to see some way to conditionally include wiki text based on
whether the wiki enables or disables certain features. For example,
-[[ikiwiki/formatting]], could use `\[[if (enabled smiley) """Also, because
+[[ikiwiki/formatting]], could use `\[[!if (enabled smiley) """Also, because
this wiki has the smiley plugin enabled, you can insert \[[smileys]] and
some other useful symbols."""]]`, and a standard template for [[plugins]]
pages could check for the given plugin name to print "enabled" or
`then`.
Syntax could vary greatly here, both for the
-[[ikiwiki/PreprocessorDirective]] and for the condition itself.
+[[ikiwiki/Directive]] and for the condition itself.
> I think this is a good thing to consider, although conditionals tend to
> make everything a lot more complicated, so I also want to KISS, and not
> As to the syntax, to fit it into standard preprocessor syntax, it would
> need to look something like this:
>
-> \[[if test="enabled(smiley)" """foo"""]]
+> \[[!if test="enabled(smiley)" """foo"""]]
>
> --[[Joey]]
>> [[ikiwiki/PageSpec]] syntax seems perfect, and your proposed syntax for the `if`
->> [[ikiwiki/PreprocessorDirective]] looks fine to me.
+>> [[ikiwiki/Directive]] looks fine to me.
>>
>> [[ikiwiki/PageSpec]]s don't give you `none` for free, since `!foo/*` as a boolean
>> would mean "does any page not matching `foo/*` exist", not "does `foo/*`
>>
>> A few use cases for `included`, which I would really like to see:
>>
->> * On the sidebar page, you could say something like \[[if test="!included"
+>> * On the sidebar page, you could say something like \[[!if test="!included"
>> """This page, without this help message, appears as a sidebar on all
>> pages."""]]. The help text would then only appear on the sidebar page
>> itself, not the sidebar included on all pages.
>>
->> * On [[ikiwiki/blog]] entries, you could use `included` to implement a cut.
+>> * On [[blog]] entries, you could use `included` to implement a cut.
>> (Please don't take that as an argument against. :) ) For instance, you
>> could use included rather than [[plugins/toggle]] for the detailed
>> changelogs of ikiwiki, or to embed an image as a link in the feed rather
--[[Joey]]
> You rock mightily. --[[JoshTriplett]]
+
+Is there a way to test features other than plugins? For example,
+to add to [[ikiwiki/Markdown]] something like
+
+ \[[!if test="enabled(multimarkdown)" then="You can also use..."]]
+
+(I tried it like that just to see if it would work, but I wasn't that lucky.)
+--ChapmanFlack
+
+> No, not supported. I really think that trying to conditionalise text on a
+> page for multimarkdown is a path to madness or unreadability though.
+> Perhaps it would be better to have .mmdwn files that can only contain
+> multimarkdown? --[[Joey]]
+
+>> Really, there was only one (or maybe two) pages I had in mind as appropriate
+>> places for conditional text based on multimarkdown—the underlay pages
+>> for 'markdown' and maybe also 'formatting', because those are the pages you
+>> look at when you're trying to find out how to mark stuff up for the wiki, so
+>> if MM is enabled, they need to at least mention it and have a link to the
+>> MM syntax guide.--ChapmanFlack
[[conditional_text_based_on_ikiwiki_features]] available, ikiwiki could
parse a page like conditionalpages.mdwn, which could contain a set of
conditional-wrapped page names; that seems like the most elegant and
-ikiwiki-like approach. Alternatively, [[/ikiwiki.setup]] could contain a
+ikiwiki-like approach. Alternatively, ikiwiki.setup could contain a
Perl-generated exclude option by default; that would work, but it seems
hackish.
This is nice for shared hosting, and other situation where the user doesn't have control over the server timezone.
> [[done]] via the ENV setting in the setup file. --[[Joey]]
+
+
+Example (ikiwiki.setup):
+
+ ENV => { TZ => "Europe/Sofia" }
--- /dev/null
+I think the following would be useful. Have a plugin (pagecopyright? dunno about the name), configured
+by an "association-list"
+<pre>
+copyright_alist=>[ "*/Discussion" => "Comments copyright individual authors",
+ "*"=> "Copyright 2008 Widget Co" ]
+</pre>
+
+And yes, I know about [[plugins/contrib/default_content_for___42__copyright__42___and___42__license__42__]]
+
+[[DavidBremner]]
[[done]] --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
-[[Blog|ikiwiki/blog]] feeds and index pages show the posted time (ctime), the actual blog entry pages only show the modified time.
+[[Blog]] feeds and index pages show the posted time (ctime), the actual blog entry pages only show the modified time.
The user has to look at the history link to find when a blog item was posted.
> I've committed a change that adds a CTIME variable to page.tmpl. I left
> it commented out in the default template, since it seems like a bit of
> clutter to me. Good enough? --[[Joey]]
+
+[[done]]
-Here's Thomas Schwinge unfinished darcs support for ikiwiki.
-
-(Finishing this has been suggested as a [[soc]] project.)
-
-> I haven't been working on this for months and also won't in the near
-> future. Feel free to use what I have done so
-> far and bring it into an usable state! Also, feel free to contact me
-> if there are questions.
-
--- [Thomas Schwinge](mailto:tschwinge@gnu.org)
-
-[[toggle text="show"]]
-[[toggleable text="""
- # Support for the darcs rcs, <URL:http://darcs.net/>.
- # Copyright (C) 2006 Thomas Schwinge <tschwinge@gnu.org>
- #
- # This program is free software; you can redistribute it and/or modify it
- # under the terms of the GNU General Public License as published by the
- # Free Software Foundation; either version 2 of the License, or (at your
- # option) any later version.
- #
- # This program is distributed in the hope that it will be useful, but
- # WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program; if not, write to the Free Software Foundation, Inc.,
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-
- # We're guaranteed to be the only instance of ikiwiki running at a given
- # time. It is essential that only ikiwiki is working on a particular
- # repository. That means one instance of ikiwiki and it also means that
- # you must not `darcs push' into this repository, as this might create
- # race conditions, as I understand it.
-
-
- use warnings;
- use strict;
- use IkiWiki;
-
- package IkiWiki;
-
-
- # Which darcs executable to use.
- my $darcs = ($ENV{DARCS} or 'darcs');
-
-
- # Internal functions.
-
- sub darcs_info ($$$) {
- my $field = shift;
- my $repodir = shift;
- my $file = shift; # Relative to the repodir.
-
- my $child = open(DARCS_CHANGES, "-|");
- if (! $child) {
- exec($darcs, 'changes', '--repo=' . $repodir, '--xml-output', $file) or
- error('failed to run `darcs changes\'');
- }
-
- # Brute force for now. :-/
- while (<DARCS_CHANGES>) {
- last if /^<\/created_as>$/;
- }
- ($_) = <DARCS_CHANGES> =~ /$field=\'([^\']+)/;
- $field eq 'hash' and s/\.gz//; # Strip away the `.gz' from `hash'es.
-
- close(DARCS_CHANGES) or error('`darcs changes\' exited ' . $?);
-
- return $_;
- }
-
-
- # Exported functions.
-
- sub rcs_update () {
- # Not needed.
- }
-
- sub rcs_prepedit ($) {
- # Prepares to edit a file under revision control. Returns a token that
- # must be passed to rcs_commit() when the file is to be commited. For us,
- # this token the hash value of the latest patch that modifies the file,
- # i.e. something like its current revision. If the file is not yet added
- # to the repository, we return TODO: the empty string.
-
- my $file = shift; # Relative to the repodir.
-
- my $hash = darcs_info('hash', $config{srcdir}, $file);
- return defined $hash ? $hash : "";
- }
-
- sub rcs_commit ($$$) {
- # Commit the page. Returns `undef' on success and a version of the page
- # with conflict markers on failure.
-
- my $file = shift; # Relative to the repodir.
- my $message = shift;
- my $rcstoken = shift;
-
- # Compute if the ``revision'' of $file changed.
- my $changed = darcs_info('hash', $config{srcdir}, $file) ne $rcstoken;
-
- # Yes, the following is a bit convoluted.
- if ($changed) {
- # TODO. Invent a better, non-conflicting name.
- rename("$config{srcdir}/$file", "$config{srcdir}/$file.save") or
- error("failed to rename $file to $file.save: $!");
-
- # Roll the repository back to $rcstoken.
-
- # TODO. Can we be sure that no changes are lost? I think that
- # we can, if we make sure that the `darcs push' below will always
- # succeed.
-
- # We need to revert everything as `darcs obliterate' might choke
- # otherwise.
- # TODO: `yes | ...' needed? Doesn't seem so.
- system($darcs, "revert", "--repodir=" . $config{srcdir}, "--all") and
- error("`darcs revert' failed");
- # Remove all patches starting at $rcstoken.
- # TODO. Something like `yes | darcs obliterate ...' seems to be needed.
- system($darcs, "obliterate", "--quiet", "--repodir" . $config{srcdir},
- "--match", "hash " . $rcstoken) and
- error("`darcs obliterate' failed");
- # Restore the $rcstoken one.
- system($darcs, "pull", "--quiet", "--repodir=" . $config{srcdir},
- "--match", "hash " . $rcstoken, "--all") and
- error("`darcs pull' failed");
-
- # We're back at $rcstoken. Re-install the modified file.
- rename("$config{srcdir}/$file.save", "$config{srcdir}/$file") or
- error("failed to rename $file.save to $file: $!");
- }
-
- # Record the changes.
- # TODO: What if $message is empty?
- writefile("$file.log", $config{srcdir}, $message);
- system($darcs, 'record', '--repodir=' . $config{srcdir}, '--all',
- '--logfile=' . "$config{srcdir}/$file.log",
- '--author=' . 'web commit <web-hurd@gnu.org>', $file) and
- error('`darcs record\' failed');
-
- # Update the repository by pulling from the default repository, which is
- # master repository.
- system($darcs, "pull", "--quiet", "--repodir=" . $config{srcdir},
- "--all") and error("`darcs pull' failed\n");
-
- # If this updating yields any conflicts, we'll record them now to resolve
- # them. If nothing is recorded, there are no conflicts.
- $rcstoken = darcs_info('hash', $config{srcdir}, $file);
- # TODO: Use only the first line here, i.e. only the patch name?
- writefile("$file.log", $config{srcdir}, 'resolve conflicts: ' . $message);
- system($darcs, 'record', '--repodir=' . $config{srcdir}, '--all',
- '--logfile=' . "$config{srcdir}/$file.log",
- '--author=' . 'web commit <web-hurd@gnu.org>', $file) and
- error('`darcs record\' failed');
- my $conflicts = darcs_info('hash', $config{srcdir}, $file) ne $rcstoken;
- unlink("$config{srcdir}/$file.log") or
- error("failed to remove `$file.log'");
-
- # Push the changes to the main repository.
- system($darcs, 'push', '--quiet', '--repodir=' . $config{srcdir}, '--all')
- and error('`darcs push\' failed');
- # TODO: darcs send?
-
- if ($conflicts) {
- my $document = readfile("$config{srcdir}/$file");
- # Try to leave everything in a consistent state.
- # TODO: `yes | ...' needed? Doesn't seem so.
- system($darcs, "revert", "--repodir=" . $config{srcdir}, "--all") and
- warn("`darcs revert' failed.\n");
- return $document;
- } else {
- return undef;
- }
- }
-
- sub rcs_add ($) {
- my $file = shift; # Relative to the repodir.
-
- # Intermediate directories will be added automagically.
- system($darcs, 'add', '--quiet', '--repodir=' . $config{srcdir},
- '--boring', $file) and error('`darcs add\' failed');
- }
-
- sub rcs_recentchanges ($) {
- warn('rcs_recentchanges() is not implemented');
- return 'rcs_recentchanges() is not implemented';
- }
-
- sub rcs_notify () {
- warn('rcs_notify() is not implemented');
- }
-
- sub rcs_getctime () {
- warn('rcs_getctime() is not implemented');
- }
-
- 1
-"""]]
-
-This is my ([bma](bma@bmalee.eu)) darcs.pm - it's messy (my Perl isn't up to much) but seems to work. It uses just one repo, like the mercurial plugin (unlike the above version, which AIUI uses two).
-
-`rcs_commit()` uses backticks instead of `system()`, to prevent darcs' output being sent to the browser and mucking with the HTTP headers (`darcs record` has no --quiet option). And `rcs_recentchanges()` uses regexes rather than parsing darcs' XML output.
-
-[[toggle text="show" id="bma"]]
-[[toggleable id="bma" text="""
-
- #!/usr/bin/perl
-
- use warnings;
- use strict;
- use IkiWiki;
- use Date::Parse;
- use open qw{:utf8 :std};
-
- package IkiWiki;
-
- sub rcs_update () { #{{{
- # Do nothing - there's nowhere to update *from*.
- } #}}}
-
- sub rcs_prepedit ($) { #{{{
- } #}}}
-
- sub rcs_commit ($$$;$$) { #{{{
- my ($file, $message, $rcstoken, $user, $ipaddr) = @_;
-
- # $user should probably be a name and an email address, by darcs
- # convention.
- if (defined $user) {
- $user = possibly_foolish_untaint($user);
- }
- elsif (defined $ipaddr) {
- $user = "Anonymous from $ipaddr";
- }
- else {
- $user = "Anonymous";
- }
-
- $message = possibly_foolish_untaint($message);
-
- # BUG: this outputs one line of text, and there's not a -q or --quiet
- # option. Redirecting output to /dev/null works, but I still get the
- # HTTP status and location headers displayed in the browser - is that
- # darcs' fault or ikiwiki's?
- # Doing it in backticks *works*, but I'm sure it could be done better.
- my @cmdline = ("darcs", "record", "--repodir", "$config{srcdir}",
- "-a", "-m", "$message", "--author", "$user", $file);
- `darcs record --repodir "$config{srcdir}" -a -m "$message" --author "$user" $file`; # Return value? Output? Who needs 'em?
- #if (system(@cmdline) != 0) {
- # warn "'@cmdline' failed: $!";
- #}
-
- return undef; # success
-
- sub rcs_add ($) { # {{{
- my ($file) = @_;
-
- my @cmdline = ("darcs", "add", "--repodir", "$config{srcdir}", "-a", "-q", "$file");
- if (system(@cmdline) != 0) {
- warn "'@cmdline' failed: $!";
- }
- } #}}}
-
- sub rcs_recentchanges ($) { #{{{
- # TODO: This is horrible code. It doesn't work perfectly, and uses regexes
- # rather than parsing Darcs' XML output.
- my $num=shift;
- my @ret;
-
- return unless -d "$config{srcdir}/_darcs";
-
- my $changelog = `darcs changes --xml --summary --repodir "$config{srcdir}"`;
- $changelog = join("", split(/\s*\n\s*/, $changelog));
- my @changes = split(/<\/patch>.*?<patch/m, $changelog);
-
-
- foreach my $change (@changes) {
- $change =~ m/hash='(.*?)'/;
- my $rev = $1;
- $change =~ m/author='(.*?)'/;
- my $user = $1."\n";
- my $committype = "web";
- if($user =~ m/</) {
- # Author fields generated by darcs include an email address: look for the "<".
- $committype = "darcs";
- use HTML::Entities;
- $user = decode_entities $user;
- }
- $change =~ m/local_date='(.*?)'/;
- my $when = $1;
- $when=time - str2time($when, 'UTC');
- $change =~ m/<name>(.*?)<\/name>/g;
- my @message = {line => $1};
- foreach my $match ($change =~ m/<comment>(.*?)<\/comment>/gm) {
- push @message, {line => $1};
- }
-
- my @pages;
- foreach my $match ($change =~ m/<.*?_(file|directory)>(.*?)(<(added|removed)_lines.*\/>)*<\/.*?_(file|directory)>/g) {
- # My perl-fu is weak. I'm probably going about this all wrong, anyway.
- push @pages, {page => pagename($match)} if ( -f $config{srcdir}."/".$match || -d $config{srcdir}."/".$match) and not $match =~ m/^$/;
- }
- push @ret, { rev => $rev,
- user => $user,
- committype => $committype,
- when => $when,
- message => [@message],
- pages => [@pages],
- }
- }
- return @ret;
- } #}}}
-
- sub rcs_notify () { #{{{
- # TODO
- } #}}}
-
- sub rcs_getctime ($) { #{{{
- error gettext("getctime not implemented");
- } #}}}
-
- 1
-
-
-
-"""]]
-
----
-
-Well, here's my version too. It only does getctime -- using a real XML parser, instead of regexp ugliness -- and maybe recentchanges, but that may be bitrotted, or maybe I never finished it, as I only need the getctime. As for actual commits, I have previously voiced my opinion, that this should be done by the plugin generating a patch bundle, and forwarding it to darcs in some way (`darcs apply` or even email to another host, possibly moderated), instead of the hacky direct modification of a working copy. It could also be faster to getctime in a batch. Just reading in all the changes the first time they're needed, might not be a big improvement in many cases, but if we got a batch request from ikiwiki, we could keep reaing the changes until all the files in this batch request have been met. --[[tuomov]]
-
-[[toggle text="show" id="tuomov"]]
-[[toggleable id="tuomov" text="""
-<pre>
-#!/usr/bin/perl
-# Stubs for no revision control.
-
-use warnings;
-use strict;
-use IkiWiki;
-
-package IkiWiki;
-
-sub rcs_update () {
-}
-
-sub rcs_prepedit ($) {
- return ""
-}
-
-sub rcs_commit ($$$) {
- return undef # success
-}
-
-sub rcs_add ($) {
-}
-
-sub rcs_recentchanges ($) {
- my $num=shift;
- my @ret;
-
- eval q{use Date::Parse};
- eval q{use XML::Simple};
-
- my $repodir=$config{srcdir};
-
- if (-d "$config{srcdir}/_darcs") {
- my $child = open(LOG, "-|");
- if (! $child) {
- exec("darcs", "changes", "--xml",
- "--repodir", "$repodir",
- "--last", "$num")
- || error("darcs changes failed to run");
- }
- my $data=<LOG>;
- close LOG;
-
- my $log = XMLin($data, ForceArray => 1);
-
- foreach my $patch ($log->{patch}) {
- my $date=$patch->{local_date};
- my $hash=$patch->{hash};
- my $when=concise(ago(time - str2time($date)));
- my @pages;
-
- my $child = open(SUMMARY, "-|");
- if (! $child) {
- exec("darcs", "annotate", "-s", "--xml",
- "--match", "hash: $hash",
- "--repodir", "$repodir")
- || error("darcs annotate failed to run");
- }
- my $data=<SUMMARY>;
- close SUMMARY;
-
- my $summary = XMLin("<lame>$data</lame>", ForceArray => 1);
-
- # TODO: find @pages
-
- push @ret, {
- #rev => $rev,
- user => $patch->{author},
- #committype => $committype,
- when => $when,
- #message => [@message],
- pages => [@pages],
- }; # if @pages;
- return @ret if @ret >= $num;
- }
- }
-
- return @ret;
-}
-
-sub rcs_notify () {
-}
-
-sub rcs_getctime ($) {
- my $file=shift;
-
- eval q{use Date::Parse};
- eval q{use XML::Simple};
- local $/=undef;
-
- # Sigh... doing things the hard way again
- my $repodir=$config{srcdir};
-
- my $filer=substr($file, length($repodir));
- $filer =~ s:^[/]+::;
-
- my $child = open(LOG, "-|");
- if (! $child) {
- exec("darcs", "changes", "--xml", "--reverse",
- "--repodir", "$repodir", "$filer")
- || error("darcs changes $filer failed to run");
- }
-
- my $data=<LOG>;
- close LOG;
-
- my $log = XMLin($data, ForceArray => 1);
-
- my $datestr=$log->{patch}[0]->{local_date};
-
- if (! defined $datestr) {
- warn "failed to get ctime for $filer";
- return 0;
- }
-
- my $date=str2time($datestr);
-
- debug("found ctime ".localtime($date)." for $file");
-
- return $date;
-}
-
-1
-</pre>
-"""]]
-
----
-
-I merged the two versions above and made some fixes; it is recording my web edits in darcs and showing a recent changes page.
-It is in a [darcs repository](http://joyful.com/darcsweb/darcsweb.cgi?r=ikiwiki-darcs), please send patches. --[[Simon_Michael]]
-
-> I'd like to see at least the following fixed before I commit this: --[[Joey]]
-> * Running `darcs record $filename` in backticks is not good (security)
-> The thing to do is to open stdout to /dev/null before execing darcs.
-> * Get `rcs_recentchanges_xml` working, parsing xml with regexps does
-> not seem like a maintenance win.
-> * `rcs_notify` should be removed, it's no longer used.
-> * Some form of conflict handling. Using darcs to attempt to merge
-> the changes is I gusss optional (although every other rcs backend,
-> including svn manages to do this), but it needs to at *least* detect
-> conflicts and return a page with conflict markers for the user to fix
-> the conflict.
-
-[[tag patch]]
+<http://khjk.org/~pesco/ikiwiki-darcs/> (now a darcs repo)
+
+I've taken all the good stuff from the above (now deleted --[[Joey]]) and added the missing hooks. The code hasn't seen a lot of testing, so some bugs are likely yet to surface. Also, I'm not experienced with perl and don't know where I should have used the function `possibly_foolish_untaint`.
+
+> Review of this one:
+>
+> * Should use tab indentation. (fixed)
+> * `rcs_getctime` should not need to use a ctime cache (such a cache should
+> also not be named `.ikiwiki.ctimes`). `rcs_getctime` is run exactly
+> once per page, ever, and the data is cached in ikiwiki's index. (fixed)
+> * I doubt that ENV{DARCS} will be available, since the wrapper clobbers> the entire
+> environment. I'd say remove that. (fixed)
+> * I don't understand what `darcs_info` is doing, but it seems to be
+> parsing xml with a regexp?
+> * Looks like `rcs_commit` needs a few improvements, as marked TODO
+> * `rcs_remove` just calls unlink? Does darcs record notice the file was removed
+> and automatically commit the removal?
+> * Is the the darcs info in [[rcs/details]] still up-to-date re this version? (fixed)
+> --[[Joey]]
+
+> Update:
+>
+> I think I've addressed all of the above except for the XML parsing in `darcs_info`.
+> The function determines the md5 hash of the last patch the given file appears in.
+> That's indeed being done with regexps but my Perl isn't good enough for a quick recode
+> right now.
+>
+> As for the darcs info in [[rcs/details]], it does not accurately describe the way
+> this version works. It's similar, but the details differ slightly.
+> You could copy my description above to replace it.
+>
+>> done --[[Joey]]
+>
+> There is still some ironing to do, for instance the current version doesn't allow for
+> modifying attachments by re-uploading them via CGI ("darcs add failed"). Am I assuming
+> correctly that "adding" a file that's already in the repo should just be a no-op?
+> --pesco
+
+>> It should result in the new file contents being committed by
+>> `rcs_commit_staged`. For some revision control systems, which
+>> automatically commit modifications, it would be a no-op. --[[Joey]]
+
+>>> Done. --pesco
+
+----
+
+I've finally merged this into ikiwiki master. The plugin looks quite
+complete, with only the new `rcs_receive` hook missing, and I
+hope it works as good as it looks. :) If anyone wants to work on improving
+it, there are some TODOs as mentioned above that could still be improved.
+--[[Joey]]
+
+[[!tag patch done]]
+use strict;
+use IkiWiki;
+
-+sub import { #{{{
++sub import {
+ hook(type => "pagetemplate", id => "datearchives", call => \&pagetemplate, scan => 1);
-+} # }}}
++}
+
-+sub pagetemplate (@) { #{{{
++sub pagetemplate (@) {
+ my %args = @_;
+ my $dt;
+ eval {
+ $template->param(ctime => htmllink( $args{page}, $args{destpage}, $link, 0, 0,
+ $template->param('ctime')));
+ }
-+} # }}}
++}
+
+1
</pre>
>>> might move it to the contributed plugins directory as it's a bit
>>> specialised to be included in ikiwiki though. --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
+ $PLUCENE_DIR = $config{wikistatedir}.'/plucene';
+}
+
- sub import { #{{{
+ sub import {
- hook(type => "getopt", id => "hyperestraier",
- call => \&getopt);
- hook(type => "checkconfig", id => "hyperestraier",
call => \&change);
- hook(type => "cgi", id => "hyperestraier",
- call => \&cgi);
- } # }}}
+ }
--sub getopt () { #{{{
+-sub getopt () {
- eval q{use Getopt::Long};
- error($@) if $@;
- Getopt::Long::Configure('pass_through');
- GetOptions("estseek=s" => \$config{estseek});
--} #}}}
+-}
+sub writer {
+ init();
+ grep { defined pagetype($_) } @_;
+}
+
- sub checkconfig () { #{{{
+ sub checkconfig () {
foreach my $required (qw(url cgiurl)) {
if (! length $config{$required}) {
@@ -36,112 +58,55 @@
}
- } #}}}
+ }
-my $form;
--sub pagetemplate (@) { #{{{
+-sub pagetemplate (@) {
- my %params=@_;
- my $page=$params{page};
- my $template=$params{template};
+#my $form;
-+#sub pagetemplate (@) { #{{{
++#sub pagetemplate (@) {
+# my %params=@_;
+# my $page=$params{page};
+# my $template=$params{template};
+#
+# $template->param(searchform => $form);
+# }
-+#} #}}}
++#}
- # Add search box to page header.
- if ($template->query(name => "searchform")) {
-
- $template->param(searchform => $form);
- }
--} #}}}
+-}
-
- sub delete (@) { #{{{
+ sub delete (@) {
- debug(gettext("cleaning hyperestraier search index"));
- estcmd("purge -cl");
- estcfg();
+ $reader->delete_term( Plucene::Index::Term->new({ field => "id", text => $_ }));
+ }
+ $reader->close;
- } #}}}
+ }
- sub change (@) { #{{{
+ sub change (@) {
- debug(gettext("updating hyperestraier search index"));
- estcmd("gather -cm -bc -cl -sd",
- map {
+ $doc->add(Plucene::Document::Field->UnStored('text' => $data));
+ $writer->add_document($doc);
+ }
- } #}}}
+ }
-
--sub cgi ($) { #{{{
+-sub cgi ($) {
- my $cgi=shift;
-
- if (defined $cgi->param('phrase') || defined $cgi->param("navi")) {
- chdir("$config{wikistatedir}/hyperestraier") || error("chdir: $!");
- exec("./".IkiWiki::basename($config{cgiurl})) || error("estseek.cgi failed");
- }
--} #}}}
+-}
-
-my $configured=0;
--sub estcfg () { #{{{
+-sub estcfg () {
- return if $configured;
- $configured=1;
-
- unlink($cgi);
- my $estseek = defined $config{estseek} ? $config{estseek} : '/usr/lib/estraier/estseek.cgi';
- symlink($estseek, $cgi) || error("symlink $estseek $cgi: $!");
--} # }}}
+-}
-
--sub estcmd ($;@) { #{{{
+-sub estcmd ($;@) {
- my @params=split(' ', shift);
- push @params, "-cl", "$config{wikistatedir}/hyperestraier";
- if (@_) {
- open(STDOUT, "/dev/null"); # shut it up (closing won't work)
- exec("estcmd", @params) || error("can't run estcmd");
- }
--} #}}}
+-}
-
-1
+1;
--- /dev/null
+The current basewiki is not [[self-documenting|todo/basewiki_should_be_self_documenting]]. In particular, if
+[[plugins/listdirectives]] is used, it creates a list with a bunch of
+broken links to directives/*, pages that do not currently exist in the
+docwiki or basewiki.
+
+This could be fixed by adding a page for each directive under to
+`ikiwiki/directives`, and put those into a new underlay, which the plugin
+could enable. Rather a lot of work and maintenance to document all the
+directives like that.
+
+I also considered having it link to the plugin that defined the
+directive. Then all the plugins can be included in a new underlay, which
+both [[plugins/listdirectives]] and [[plugins/websetup]] could enable.
+(The latter could be improved by making the plugin names in the web setup
+be links to docs about each plugin..)
+
+The problem I ran into doing that is that the existing plugin pages have a
+lot of stuff on them you probably don't want an underlay doing. The biggest
+issues were wikilinks to other pages in the docwiki (which would end up
+broken if the plugins were used as an underlay), and plugin pages that
+include examples of the plugin in use, which are sometimes rather expensive
+(eg, brokenlinks).
+
+Either way requires a lot of reorganisation/doc work, and an onging
+maintenance load.
+
+> Which has now been [[done]]. -- [[Will]]
+
+BTW, this patch would be needed for the second approach, to allow
+listdirectives to map from preprocessor directives back to the plugin that
+defined them: --[[Joey]]
+
+ commit 0486b46a629cae19ce89492d5ac498bbf9b84f5f
+ Author: Joey Hess <joey@kodama.kitenet.net>
+ Date: Mon Aug 25 15:38:51 2008 -0400
+
+ record which plugins registered which hooks
+
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index e476521..afe982a 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -493,6 +493,7 @@ sub loadplugins () {
+ return 1;
+ }
+
+ +my $loading_plugin;
+ sub loadplugin ($) {
+ my $plugin=shift;
+
+ @@ -502,14 +503,18 @@ sub loadplugin ($) {
+ "$installdir/lib/ikiwiki") {
+ if (defined $dir && -x "$dir/plugins/$plugin") {
+ require IkiWiki::Plugin::external;
+ + $loading_plugin=$plugin;
+ import IkiWiki::Plugin::external "$dir/plugins/$plugin";
+ + $loading_plugin=undef;
+ $loaded_plugins{$plugin}=1;
+ return 1;
+ }
+ }
+
+ my $mod="IkiWiki::Plugin::".possibly_foolish_untaint($plugin);
+ + $loading_plugin=$plugin;
+ eval qq{use $mod};
+ + $loading_plugin=undef;
+ if ($@) {
+ error("Failed to load plugin $mod: $@");
+ }
+ @@ -1429,6 +1434,9 @@ sub hook (@) {
+
+ return if $param{no_override} && exists $hooks{$param{type}}{$param{id}};
+
+ + # Record which plugin was being loaded when the hook was defined.
+ + $param{plugin}=$loading_plugin if defined $loading_plugin;
+ +
+ $hooks{$param{type}}{$param{id}}=\%param;
+ return 1;
+ }
Would each page be its own individual blog? Or its own blog post? To me it seems like an entire wiki can be viewed as a blog, with threaded or unthreaded comments underneath.
-[[tag soc]]
+[[!tag soc done]]
-[[inline pages="sandbox/castle/discussion/* and !sandbox/castle/discussion/*/*" rootpage="sandbox/castle/discussion"]]
\ No newline at end of file
+[[!inline pages="sandbox/castle/discussion/* and !sandbox/castle/discussion/*/*" rootpage="sandbox/castle/discussion"]]
\ No newline at end of file
I don't like foo. Have you tried living without foo?
-[[inline pages="sandbox/castle/discussion/Don__39__t_like_foo/*" rootpage="sandbox/castle/discussion/Don__39__t_like_foo"]]
\ No newline at end of file
+[[!inline pages="sandbox/castle/discussion/Don__39__t_like_foo/*" rootpage="sandbox/castle/discussion/Don__39__t_like_foo"]]
\ No newline at end of file
recently fixed [[TODO]] items
-[[inline pages="link(todo/done) and !todo and !*/Discussion" sort=mtime show=10]]
+[[!inline pages="link(todo/done) and !todo and !*/Discussion" sort=mtime show=10 archive=yes]]
-[[tag wishlist]]
+[[!tag wishlist]]
Given that ikiwiki has a suggested use as a tool for developers, I was thinking it might be cool if ikiwiki had [Doxygen](http://www.doxygen.org/) support. I'm not exactly sure how the integration would work. Something along the lines of a plugin to support .dox files would be my first thought. I'd leave generating the documentation from any source files for a separate run of Doxygen - it'd be easier and you probably don't want the source being edited over the web.
>>> Seems like a job for good ol' string interpolation. rootpage="post/$current_year/$current_month/$current_day"
>>> Ikiwiki could provide some vars, and it would be nice to write plugins to also provide vars. Sort of like templates.
>>> Does that feel OK? --[[sabr]]
+
+> I want the exact same thing. My compromise was to create a `datedblog` module which overrides `inline`'s `sessioncgi` hook
+> with something that sets the new page name to `%Y-%m-%d.$page` and sets up a meta directive at the beginning of
+> the content, with the title you wanted. Now if you use the `datedblog` module, you get dated blog entries. But I'd
+> like to have traditional `inline` functionality too. This would work great if there were a way to change the `do`
+> parameter in the `blogpost` template's form; if I could change it to `datedblog` instead of `blog` then I could hook
+> my datedblog module in nicely, without having to override anything. What would be the right way to do that? --[[neale]]
+
+> This is basically the same request as
+> [[todo/inline_postform_autotitles]]. --[[smcv]]
--- /dev/null
+At the moment the text area in the edit form has a fixed size of 20 rows.
+
+On longer pages its not very comfortable to edit pages with such a small box. The whole screen size should be used instead([example](http://img3.imagebanana.com/img/bl10u9mb/editingtodo_1241804460828.png)).
+
+> The whole screen width is used, via the following
+> from style.css:
+>
+> {
+> width: 100%;
+> }
+>
+> Perhaps you have replaced it with a modified style sheet that does not
+> include that? --[[Joey]] [[!tag done]]
+
+>> The screen shot was made with http://ikiwiki.info/ where i didn't change anything. The width is optimally used. The problem is the height.
+
+>>> You confused me by talking about rows...
+>>> I don't know how to allow CSS to resize a textarea
+>>> to the full browser height. The obvious `height: 75%;`
+>>> does not work, at least in firefox and epiphany.
+>>>
+>>> Ah, of course, if it did work, it'd make it be 75% of
+>>> the full *page* height, and not the browser window height.
+>>>
+>>> According to
+>>> [this page](http://stackoverflow.com/questions/632983/css-height-if-textarea-as-a-percentage-of-the-viewport-height):
+>>>>>50% of what? Parent says ‘auto’, which means base it on the height of the child content. Which depends on the height on the parent. Argh! etc.
+>>>>>
+>>>>>So you have to give its parent a percentage height. And the parent's parent, all the way up to the root.
+>>> So, other than a javascript-based resizer, some very tricky and invasive CSS
+>>> seems to be needed. Please someone let me know if you succeed in doing that.
+>>> --[[Joey]]
+
+>>>>>> the javascript approach would need to work something like this: you need to know about the "bottom-most" item on the edit page, and get a handle for that object in the DOM. You can then obtain the absolute position height-wise of this element and the absolute position of the bottom of the window to determine the pixel-difference. Then, you set the height of the textarea to (current height in px) + determined-value. This needs to be re-triggered on various resize events, at least for the window and probably for other elements too. I may have a stab at this at some point. -- [[Jon]]
--- /dev/null
+[[!tag patch done]]
+
+[[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]]
+
+> Can't a [[plugins/conditional]] be for this?
+> --[[Joey]]
+
+>> Hmmm, what do you mean? Adding a syntax such as the one below?
+>> Or something else?
+
+ \[[!if test="map(" then="..." else="..."]]
+
+>> What would you write in the `then` clause?
+>> I'm not opposed at all to rewrite my two-liner, but I don't understand.
+>> --[[intrigeri]]
+
+ \[[!if test="foo/*" then="""
+ [[!map pages="foo/*"]]
+ """ else="no pages"]]
+
+--[[Joey]]
+
+>>> I'm not convinced: the syntax you're proposing implies to duplicate
+>>> the pagespec (once in the test clause, and once in the map query), which I find
+>>> not only inelegant, which I can live with, but also tiring and unpractical:
+>>> my `else` suggestion
+>>> finds its roots in map queries with rather long pagespecs. On the other
+>>> hand, if I'm the only one using map in such a way, I can live with this
+>>> heavy duplicated syntax without bloating the map plugin with features
+>>> no-one but me needs. On the other other hand, the patch is a 3-liner.
+>>> I'm not fixed yet, I'll think about it. --[[intrigeri]]
+
+>>>> Write a [[plugins/template]] which accepts a pagespec and an
+>>>> "else" clause, and then you won't have to duplicate the
+>>>> pagespec. --[[JoshTriplett]]
+
+>>>> Yeah, the patch is obviously very simple. My problem with it really is
+>>>> that there would seem to be several other places in ikiwiki where
+>>>> someone might want to be able to handle an "else" case where a
+>>>> pagespec expands to nothing. And adding else cases for all of them
+>>>> could be a bit much. --[[Joey]]
+
+>>>>> Agreed, and tagging as done. For the record, here is the [[plugins/template]] I use:
+
+ \[[!if test="<TMPL_VAR raw_pages>"
+ then="""<TMPL_VAR intro>
+ [[!map pages="<TMPL_VAR raw_pages>"]]"""
+ else="<TMPL_VAR else>"]]
+
+>>>>> --[[intrigeri]]
@@ -26,7 +26,7 @@
memoize("file_pruned");
- sub defaultconfig () { #{{{
+ sub defaultconfig () {
- wiki_file_prune_regexps => [qr/\.\./, qr/^\./, qr/\/\./,
+ wiki_file_prune_regexps => [qr/\.\./, qr/^\.(?!htaccess)/, qr/\/\.(?!htaccess)/,
qr/\.x?html?$/, qr/\.ikiwiki-new$/,
qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//],
wiki_link_regexp => qr/\[\[(?:([^\]\|]+)\|)?([^\s\]#]+)(?:#([^\s\]]+))?\]\]/,
-[[tag patch]]
+[[!tag patch patch/core]]
This lets the site administrator have a `.htaccess` file in their underlay
directory, say, then get it copied over when the wiki is built. Without
That way I have revision control on that file too. That may be a security concern, but I trust everybody that has svn commit
access and such .htaccess files should not be accessible through wiki cgi. Of course, it could default to 'off'.
-> See [[debbug 447267]] for a patch for this.
+> See [[!debbug 447267]] for a patch for this.
+
+>> It looks to me as though this functionality won't be included in ikiwiki
+>> unless someone who wants it takes responsibility for updating the patch
+>> from that Debian bug to be applicable to current versions, so that there's a
+>> setup file parameter for extra filenames to allow, defaulting to none
+>> (i.e. a less simplistic patch than the one at the top of this page).
+>> Joey, is this an accurate summary? --[[smcv]]
---
and htaccess is for limiting access to some areas of wiki.
It should be off by default of course. --Max
-[[tag patch]]
+---
++1 I want `.htaccess` so I can rewrite some old Wordpress URLs to make feeds work again. --[[hendry]]
+
+---
++1 for various purposes (but sometimes the filename isn't `.htaccess`, so please make it configurable) --[[schmonz]]
--- /dev/null
+There has got to be a way to run the CGI wrapper under fastcgi or modperl (apache 2). Are there easy to follow instructions describing how to set this up?
+
+> AFAIK noone has done this. One immediate problem would be permissions;
+> the CGI wrapper runs setuid to you so it can write to the wiki -- if
+> running in fastcgi/modperl I guess it would run as the web server, unless
+> there's some way to control that. So you'd need to set up the perms
+> differenly, to let the web server commit changes to the wiki.
+>
+> I've not looked at what code changes fastcgi or modperl would require in
+> ikiwiki. --[[Joey]]
+
+[[!tag wishlist]]
ikiwiki could display a reasonable message to the user, indicating what
they've done wrong.)
-[[tag soc done]]
+[[!tag soc done]]
height, compression, etc. which could be initially created by 'ikiwiki --generate-meta-stuff'.
Then PageSpec should be
teached to use these. Galleries could then be generated by means of
-\[[inline pages="type(image/*) and year(2007)" template="gallery"]]. It
+\[[!inline pages="type(image/*) and year(2007)" template="gallery"]]. It
should of course be possible to edit this information via ikiwiki.cgi and with any
text editor (Name: value). This should also allow for creations of default .html pages with
the image/video/file/... and a discussion page. Probably named image.mdwn and image/discussion.
+Reopening this for 3.0, to consider adding new functions.
+
I don't want this interface to be too firm; it's ok for a plugin like
`ddate` to redefine an internal function like IkiWiki::displaytime if it
wants to.. But plugins that still access stuff through IkiWiki:: should be
perl's type checking catching the breakage, in some cases. Plugins that
only use exported symbols should not be broken by future ikiwiki changes.
-Functions used by only some plugins, undecided about exporting:
-
-* lockwiki, unlockwiki (aggregate)
- Too internal to ever be exported.
-* loadindex (aggregate)
- Too internal to ever be exported.
-* titlepage (aggregate)
- Not until more than one thing uses it.
-* basename (polygen, inline, search, polygen)
-* dirname (linkmap, inline)
- For basename and dirname, they could just use standard perl library
- stuff. Howevever, ikiwiki's versions are slightly different and I'd
- need to check if the standard versions work for the uses made in
- these plugins. Inclined not to export.
-* abs2rel (linkmap, inline)
- This *is* the library version, just optimised to work around a bug.
- Don't export this.
-* possibly_foolish_untaint (aggregate, polygen)
- Probably better to implement yourself.
-* htmlize
-* linkify
-* preprocess
-* filter
- The 4 above are used by a few plugins, but problimatic since plugins
- typically also define functions with these names.. I also feel that
- this part of ikiwiki needs some more work before it's set in stone.
- These are always called together, in the same order, though
- sometimes htmlize isn't included.
-
-Variables used by plugins but not exported yet:
+## Most often used functions, by number of calls from plugin code
+
+ 27 IkiWiki::possibly_foolish_untaint
+
+Not very happy about exporting, it's not ikiwiki-specific,
+and plugins that need to untaint things should think about it, hard.
+
+ 12 IkiWiki::userinfo_get
+ 5 IkiWiki::userinfo_set
+
+Used by only 4 plugins, all of which are fairly core, so thinking
+don't export.
+
+ 11 IkiWiki::preprocess
+ 8 IkiWiki::filter
+ 4 IkiWiki::linkify
+ 4 IkiWiki::htmlize
+
+The page rendering chain. Note that it's very common to call `preprocess(filter(text))`,
+or `htmlize(linkify(preprocess(filter(text))))`, while `htmlize(linkify(preprocess(text))`
+is called less frequently, and it's also not unheard of to leave out a step and do
+`htmlize(preprocess(text))`. (I haven't checked if any of those cases are bugs.)
+
+It would be nice if the api could avoid exposing the details of the render chain,
+by providing a way to say "I have filtered text, and would like html", or "I have raw
+text and would like to get it up to the preprocess stage".
+
+Another problimatic thing is plugins often define functions named 'preprocess', etc.
+
+ 12 IkiWiki::linkpage
+ 11 IkiWiki::pagetitle
+ 6 IkiWiki::titlepage
+
+These go together; linkpage is needed by all link plugins, and the others are used widely.
+All should be exported. (Done)
+
+ 7 IkiWiki::saveindex
+ 5 IkiWiki::loadindex
+
+Still too internal to ever be exported?
+
+ 7 IkiWiki::redirect
+
+Only used by 4 plugins, and not in IkiWiki.pm itself, so probably not to be exported.
+
+ 7 IkiWiki::dirname
+ 4 IkiWiki::basename
+
+Not ikiwiki-specific, don't export.
+
+ 6 IkiWiki::refresh
+
+Very internal, not part of IkiWiki.pm, don't export.
+
+ 5 IkiWiki::yesno
+
+Not ikiwiki-specific, but worth exporting to get a consistent localised yes/no parser
+for directives.
+
+ 5 IkiWiki::showform
+ 4 IkiWiki::decode_form_utf8
+
+Only used by 3 fairly core plugins, not in IkiWiki.pm, don't export.
+
+ 5 IkiWiki::rcs_update
+ 4 IkiWiki::rcs_prepedit
+ 5 IkiWiki::is_admin
+ 5 IkiWiki::cgi_savesession
+ 4 IkiWiki::cgiurl
+
+Not enough use, I think, to export.
+
+ 5 IkiWiki::enable_commit_hook
+ 5 IkiWiki::disable_commit_hook
+
+Deep internal magic, if exported people will use it wrong, only used by core plugins.
+
+ 4 IkiWiki::check_canedit
+
+Probably needs to evolve more and be more widely used before being exported.
+
+## Variables used by plugins but not exported yet
* %IkiWiki::pagecase (aggregate)
-* %IkiWIki::backlinks (pagestats)
+* %IkiWiki::backlinks (pagestats)
-[[todo/done]]
+[[done]] (until 4.0)..
--Ryan Koppenhaver
## Original patch
-[[tag patch]]
+[[!tag patch patch/core plugins/rst]]
<pre>
Index: debian/changelog
print html[html.find('<body>')+6:html.find('</body>')].strip();
";
- sub import { #{{{
+ sub import {
hook(type => "htmlize", id => "rst", call => \&htmlize);
+ hook(type => "htmlescape", id => "rst", call => \&htmlescape);
+ hook(type => "htmlescapelink", id => "rst", call => \&htmlescapelink);
- } # }}}
+ }
-+sub htmlescapelink ($$;@) { #{{{
++sub htmlescapelink ($$;@) {
+ my $url = shift;
+ my $text = shift;
+ my %params = @_;
+ else {
+ return "`$text <$url>`_";
+ }
-+} # }}}
++}
+
-+sub htmlescape ($) { #{{{
++sub htmlescape ($) {
+ my $html=shift;
+ $html=~s/^/ /mg;
+ return ".. raw:: html\n\n".$html;
-+} # }}}
++}
+
- sub htmlize (@) { #{{{
+ sub htmlize (@) {
my %params=@_;
my $content=$params{content};
Index: doc/plugins/write.mdwn
-* reStructuredText does not allow raw html to be inserted into
- documents, but ikiwiki does so in many cases, including
- [[WikiLinks|ikiwiki/WikiLink]] and many
-- [[PreprocessorDirectives|ikiwiki/PreprocessorDirective]].
+- [[Directives|ikiwiki/Directive]].
+* Some bits of ikiwiki may still assume that markdown is used or embed html
+ in ways that break reStructuredText. (Report bugs if you find any.)
* It's slow; it forks a copy of python for each page. While there is a
+ return $hooks{htmlescapelink}{$type}{call}->($bestlink, $linktext);
+ }
return "<a href=\"$bestlink\">$linktext</a>";
- } #}}}
+ }
@@ -628,6 +640,14 @@
preview => $preprocess_preview,
package IkiWiki::Plugin::fortune;
use warnings;
- @@ -12,7 +18,13 @@ sub import { #{{{
+ @@ -12,7 +18,13 @@ sub import {
- sub preprocess (@) { #{{{
+ sub preprocess (@) {
$ENV{PATH}="$ENV{PATH}:/usr/games:/usr/local/games";
- my $f = `fortune 2>/dev/null`;
+ my $f;
--- /dev/null
+On the edit form when you are creating a new page, you are given an option of
+page types that can be used. The string presented to the user here is not
+particularly friendly: e.g., mdwn, txtl... it would be nice if the drop-down
+contents were "Markdown", "Textile", etc. (the values in the option tags can
+remain the same).
+
+I've written a first-take set of patches for this. They are in
+git://github.com/jmtd/ikiwiki.git in the branch "friendly_markup_names". [[!tag patch]]
+
+-- [[Jon]]
+
+[[merged|done]], TFTP! (I have not checked if any other format plugins
+would benefit from a longer name) --[[Joey]]
--- /dev/null
+[[!template id=gitbranch branch=smcv/gitignore author="[[smcv]]"]]
+[[!tag patch]]
+
+The recent merge of the po branch didn't come with a .gitignore.
+It eventually annoyed me enough to fix it :-) --[[smcv]]
+
+[[done]]
--- /dev/null
+The [[plugins/recentchanges]] plugin has a `do=recentchanges_link` feature that will
+redirect to a given wiki page, or an error page with a creation link.
+
+In the [[plugins/contrib/comments]] plugin I've found that it would be useful to do
+the same for users. For now I've just cloned the functionality into the comments
+plugin, but perhaps this functionality could be renamed to `do=goto` or
+something, and moved to `IkiWiki/CGI.pm`?
+
+> Now implemented as the 'goto' branch in my git repository, along with
+> [[apache_404_ErrorDocument_handler]]. --[[smcv]]
+
+>> Looks good, the only things I wonder are:
+>> * Should it be a separate plugin? In particular `cgi_page_from_404()` is
+>> pretty big, and only works if apache is configured so seems somewhat
+>> pluginaable.
+
+>>> I've split out `goto` and `apache404` plugins in the branch. I think
+>>> you're right that apache404 should be a plugin. If you think goto is small
+>>> and general enough to not be a plugin, just don't merge my most recent
+>>> patch! --[[smcv]]
+
+>> * I wish there were some way to generalize the workaround for the stupid
+>> MSIE behavior. Actually, I wish we could ignore the MSIE stupidity,
+>> as I tend to do, but perhaps it's too stupid in this case for that to
+>> fly..
+>> * Is there any reason to require do=goto before checking for
+>> `REDIRECT_STATUS`? Seems that if that code were moved
+>> out of the enclosing if block, the apache 404 handler could
+>> be set direct to the cgi, which seems simpler to remember.
+>> --[[Joey]]
+
+>>> No, good point - the `REDIRECT_STATUS` check is sufficiently unambiguous
+>>> already. Fixed. --[[smcv]]
+
+[[done]]
and search/sort pages by distance to a given location, as well as
showing page locations on a map (Google Map, OpenStreetMap, etc). -- [[users/vibrog]]
-[[tag wishlist]]
+[[!tag wishlist]]
+
+> [[!cpan Geo::Coordinates::UTM]] would probably be useful. --[[smcv]]
--[[Joey]]
-[[tag patch done]]
+[[!tag patch done]]
the user or by the script?), it could also set `GIT_COMMITTER_NAME` and
`GIT_COMMITTER_EMAIL` to the same values. --[[JoshTriplett]]
-> See [[debbug 451023]] for a [[patch]] --[[Joey]]
+> See [[!debbug 451023]] for a [[patch]] --[[Joey]]
+
+[[done]]
>>Sounds good to me,
>>
>> --[[harningt]]
+
+> I think the thing to do is, as Josh suggested originally, use
+> GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL. Note that setting these
+> individually is best, so git can independently validate/sanitize both
+> (which it does do somewhat). Always put the username/openid/IP in
+> GIT_AUTHOR_NAME; if the user has configured an email address,
+> GIT_AUTHOR_EMAIL can also be set.
+>
+> There is one thing yet to be solved, and that is how to tell the
+> difference between a web commit by 'Joey Hess <joey@kitenet.net>',
+> and a git commit by the same. I think we do want to differentiate these,
+> and the best way to do it seems to be to add a line to the end of the
+> commit message. Something like: "\n\nWeb-commit: true"
+>
+> For backwards compatability, the code that parses the current stuff needs
+> to be left in. But it will need to take care to only parse that if the
+> commit isn't flagged as a web commit! Else web committers could forge
+> commits from others. --[[Joey]]
+>
+> BTW, I decided not to use the user's email address in the commit, because
+> then the email becomes part of project history, and you don't really
+> expect that to happen when you give your email address on signup to a web
+> site.
+>
+> The problem with leaving the email empty is that it confuses some things
+> that try to parse it, including:
+> * cia (wants a username in there):
+> * git pull --rebase (?)
+> * github pushes to twitter ;-)
+>
+> So while I tried that way at first, I'm now leaning toward encoding the
+> username in the email address. Like "user <user@web>", or
+> "joey <http://joey.kitenet.net/@web>".
How about a plugin providing a
-[[preprocessor_directive|ikiwiki/preprocessordirective]] to render a
-[[debpkg graphviz]] file as an image via one of the graphviz programs
+[[preprocessor_directive|ikiwiki/directive]] to render a
+[[!debpkg graphviz]] file as an image via one of the graphviz programs
("dot" by default) and include the resulting image on the page, using the
"cmapx" image map format? graphviz files themselves could also render the
same way into an HTML file with the same basename as the graphviz file;
> INSTALLMAN1DIR (though MakeMaker lacks one for man8). I'd prefer not
> adding new variables where MakeMaker already has them. --[[Joey]]
-[[tag patch]]
+[[!tag patch patch/core]]
<pre>
--- /dev/null
+[[!tag wishlist]]
+
+I would like to have the possibility for hidden tags or links.
+Using the tag functionality I could group some news items for including them into other subpages. But I don't want the links or tags to show (and I don't want Tag lists like "Tags: ?mytag").
+The tagged items should not differ from the items, that are not tagged.
+I didn't find any way to hide the tag list or links and I don't want to have to create a "hidden" page containing links to the pages and then using the backlink functionality, because this is more prone to errors. It's easier to forget adding a link on a second page than forgetting to add a needed tag to a new newsitem.
+
+> I found out, that using the [[meta plugin|plugins/meta]] it is possible to create the hidden link, that I wanted.
+-- [[users/Enno]]
+
+>> Yes, [[meta link|ikiwiki/directive/meta]] will not show up as a visible link on the page, while
+>> also not showing up in the list of tags of a page, so it seems what you
+>> want. [[done]] --[[Joey]]
Because [ [inlinepage] ] isn't separated by a blank line it gets treated as a block-level element. Hmm, will this stop all formatting, including *'s to em-tags? --[[JeroenSchot]]
Ah didn't realize you meant it fixed it at the markdown level. I'll
- think about making postprocessordirectives into
- [[ikiwiki/preprocessordirective]]s instead, then I could use that fix (but I'm not
+ think about making postprocessor directives into
+ preprocessor directives instead, then I could use that fix (but I'm not
sure how feasible it is to do that). --[[Joey]]
Done.. inlining is now a preprocessor directive, happens before
--- /dev/null
+The only way to have a private ikiwiki, with a shared user database
+for static pages and CGI authentication, is to use
+[[plugins/httpauth]]. It would be good for httpauth to be on par with
+[[plugins/passwordauth]], i.e. to allow registering users, resetting
+passwords, and changing passwords; supporting some kind of
+`account_creation_password` configuration option would be nice, too.
+
+I'll probably propose patches implementing this at some point.
+I've not had a single look at the code yet, but it may be nice to factorize
+the relevant passwordauth code, instead of rewriting it completely in httpauth.
+
+-- [[intrigeri]]
+
+Well, on such a private wiki, one can neither register herself nor
+reset his password: the registration page, as any other page, would be
+forbidden to non-authenticated users. Admin users should then be
+enabled to:
+
+- register a new user
+- reset someone else's password
+
+In both cases, a brand new random password is sent by e-mail to the
+new user.
+
+An authenticated user should nevertheless be able to change his
+own password. -- [[intrigeri]]
+
+[[wishlist]]
styled uls for other things, such as the action bar, but displaying that as
a simple unstyled list in a simple browser works well and makes sense. For
parent links, it does not. --[[Joey]]
+
+[[done]]
below, concerns wanting to use foo/index.mdwn source files and get an
output page name of foo, rather than foo/index. --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
---
+++ ikidev/IkiWiki.pm 2007-02-25 15:05:22.328852000 -0800
@@ -192,6 +192,12 @@
return $untainted;
- } #}}}
+ }
- +sub titlename($;@) { #{{{
+ +sub titlename($;@) {
+ my $page = shift;
+ $page =~ s!/index$!!;
+ return pagetitle(basename($page), @_);
- +} #}}}
+ +}
+
- sub basename ($) { #{{{
+ sub basename ($) {
my $file=shift;
$page=~s/\Q.$type\E*$// if defined $type;
+ $page=~s/\/index$// if $page =~ /\/index$/;
return $page;
- } #}}}
+ }
</pre>
-This just makes it so that all files named foo/index become pages called foo, which is the desired effect. I haven't tested everything so far, so be careful! But you can see it working at http://ikidev.betacantrips.com/one/ again, as before. --Ethan
\ No newline at end of file
+This just makes it so that all files named foo/index become pages called foo, which is the desired effect. I haven't tested everything so far, so be careful! But you can see it working at http://ikidev.betacantrips.com/one/ again, as before. --Ethan
+
+[[done]], the indexpages setting enables this.
--- /dev/null
+Could you please add numerical ordering by title to [[inline|plugins/inline]]
+plugin? Now I can do only alphabetical order by title, but sometime it's not enough.
+
+> Implemented, see [[natural_sorting]] [[!tag done]] --[[Joey]]
+
+BTW, it seems that ordering by title is rather ordering by filename of page.
+For me "title" means title of page I can set using `title` parameter
+of [[meta|plugins/meta]] plugin :)
+
+Why do I need that feature? I've just been migrating an info site of our university
+[mail system](http://poczta.uw.edu.pl/) to Ikiwiki from very static, console handling
+Makefile+[WML](http://thewml.org/)+XML+XSL=HTML solution. I have many news files
+(`1.mdwn`, `2.mdwn`, etc.) and unfortunately I did very stupid thing. I've commited
+all of them in the same revision of our Subversion repo...
+
+Now I have a problem with sorting these files using inline plugin. I can't do
+sorting by age, because both old and young news files have the same age. I can't
+sort by title too. For example, when I sort them by title, then `9.mdwn` page is
+between `90.mdwn` and `89.mdwn` pages... It sucks, of course. Sorting by mtime
+also is not a solution for me, because it means that I can't touch/fix old news
+anymore.
+
+Do you have any idea how to workaround that issue? --[[Paweł|ptecza]]
+
+> Delete all files. Add files back one at a time, committing after adding
+> each file. Sort by date. --[[Joey]]
+
+>> The simplest solutions are the best :D Thanks for the hint! I didn't
+>> want to do it before, because I was affaid that my Subversion keeps
+>> old date of creation of file. --[[Paweł|ptecza]]
+
+> Maybe you can rename `9.mdwn` to `09.mdwn`? See `rename(1)`, it renames multiple files
+> in one go. --[[buo]]
+
+>> Thanks for your suggestion! But what about if number of my news files grows to 100+?
+
+>> $ ls
+>> 09.mdwn 100.mdwn 101.mdwn 102.mdwn 89.mdwn 90.mdwn
+
+>> I don't want to rename all previous files to add `0` prefix. --[[Paweł|ptecza]]
+
+>>> Rather than adding 0's or or a 'sorttype' parameter, I'd just fix the sort order.
+>>> Both MacOS and Windows use a smarter sort order than just lexical in their
+>>> file browsers (e.g. <http://support.microsoft.com/default.aspx?kbid=319827>,
+>>> <http://docs.info.apple.com/article.html?artnum=300989>).
+>>>
+>>> The [Unicode Collation algorithm](http://en.wikipedia.org/wiki/Unicode_collation_algorithm)
+>>> would seem to be a reasonable sort order. (See also <http://www.unicode.org/unicode/reports/tr10/>.)
+>>> Unfortunately the standard perl implementation, [Unicode::Collate](http://perldoc.perl.org/Unicode/Collate.html)
+>>> doesn't handle the optional [numbers](http://www.unicode.org/unicode/reports/tr10/#Customization)
+>>> extension which is what you want. --[[Will]]
+
+---
+
+Below is my simple patch. Feel free to use it or comment!
+
+I have also 2 considerations for inline sorting:
+
+1. Maybe changing name of `sort` parameter to `sortby` or `sortkey` will
+ be good idea?
+
+ > No, that would break existing wikis. --[[Joey]]
+ >> It's no problem. You just have `ikiwiki-transition` utility :D --[[Paweł|ptecza]]
+
+1. Maybe you should use `title` sort key for title from meta plugin and `name`,
+ `filename`, `page` or `pagename` for page names? In the future you can also
+ sort by meta author, license or another key.
+
+ > There are many places in ikiwiki that do not use meta title info and
+ > could. I'd prefer to deal with that issue as a whole, not here,
+ > --[[Joey]]
+
+--[[Paweł|ptecza]]
+
+ --- inline.pm-orig 2008-09-02 09:53:20.000000000 +0200
+ +++ inline.pm 2008-09-02 10:09:02.000000000 +0200
+ @@ -186,7 +186,15 @@
+ }
+
+ if (exists $params{sort} && $params{sort} eq 'title') {
+ - @list=sort { pagetitle(basename($a)) cmp pagetitle(basename($b)) } @list;
+ + if (! $params{sorttype} || $params{sorttype} eq 'lexical') {
+ + @list=sort { pagetitle(basename($a)) cmp pagetitle(basename($b)) } @list;
+ + }
+ + elsif ($params{sorttype} eq 'numeric') {
+ + @list=sort { pagetitle(basename($a)) <=> pagetitle(basename($b)) } @list;
+ + }
+ + else {
+ + return sprintf(gettext("unknown sort type %s"), $params{sorttype});
+ + }
+ }
+ elsif (exists $params{sort} && $params{sort} eq 'mtime') {
+ @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list;
+ @@ -195,7 +203,7 @@
+ @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
+ }
+ else {
+ - return sprintf(gettext("unknown sort type %s"), $params{sort});
+ + return sprintf(gettext("unknown sort key %s"), $params{sort});
+ }
+
+ if (yesno($params{reverse})) {
+
+> To users, "sort" already determines the type of sort. It can be by title,
+> or by date, etc. Adding a separate "sorttype" value is thus fairly
+> confusing. --[[Joey]]
+
+>> OK. I will be more careful when I play with inline plugin :) --[[Paweł|ptecza]]
+
+---
+
+Joey, have you forgotten about that request? ;) --[[Paweł|ptecza]]
+
+> Okie. Here is a different [[patch]] based on my comment above. It doesn't introduce
+> a new key, but rather changes the title sorting order. Two caveats:
+
+ * I've only tested this in `inline`, not the other places I changed the sort order.
+ * I'm unsure if the regexp used in the split should be `/(-?\d+)/` instead of `/(\d+)/`.
+ As written, '-' is interpreted as a hyphen rather than a minus sign.
+
+> --[[Will]]
+
+>> I"m not comfortable with tossing out perl's default collator and trying
+>> to maintain some other one going forward. Especially not for such an
+>> edge case. --[[Joey]]
+
+>> Hi Will! Your idea looks interesting for me, but I'm affraid that it's too big
+>> change in Ikiwiki... Maybe I'm wrong? ;) What do you think, Joey? --[[Paweł|ptecza]]
+
+>>> It isn't that big a change. It is just supplying a sort order to the sort. The
+>>> patch is a little larger because I then went through and made that sort
+>>> order available in other places where it makes sense. (Looking at the
+>>> patch again briefly, I should have also used it in the `map` plugin.)
+>>>
+>>> If you wanted a simple patch, you could just move the `titlecmp` function
+>>> into the inline plugin and only use it there. The problem with that is that
+>>> it only fixes the inline plugin. -- [[Will]]
+
+>>>> Will, I agree with you that it's improved way of sort order. But on the other
+>>>> hand I prefer to be careful when I change something in a several places,
+>>>> because I don't want to break any working things when I fix one thing.
+>>>> I hope that Joey agree with us too and all Ikiwiki users will be happy
+>>>> after applying your patch ;) --[[Paweł|ptecza]]
+
+----
+
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index c0f5dea..d001f8d 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -20,7 +20,7 @@ use Exporter q{import};
+ our @EXPORT = qw(hook debug error template htmlpage add_depends pagespec_match
+ bestlink htmllink readfile writefile pagetype srcfile pagename
+ displaytime will_render gettext urlto targetpage
+ - add_underlay
+ + add_underlay titlecmp
+ %config %links %pagestate %renderedfiles
+ %pagesources %destsources);
+ our $VERSION = 2.00; # plugin interface version, next is ikiwiki version
+ @@ -835,6 +835,42 @@ sub titlepage ($) {
+ return $title;
+ }
+
+ +sub titlecmp ($$) {
+ + my $titleA=shift;
+ + my $titleB=shift;
+ +
+ + my @listA=split(/(\d+)/,$titleA);
+ + my @listB=split(/(\d+)/,$titleB);
+ +
+ + while (@listA && @listB) {
+ + # compare bits of text
+ + my $a = shift @listA;
+ + my $b = shift @listB;
+ + my $c = ($a cmp $b);
+ + return $c if ($c);
+ +
+ + if (@listA && @listB) {
+ + # compare numbers
+ + $a = shift @listA;
+ + $b = shift @listB;
+ + $c = $a <=> $b;
+ + return $c if ($c);
+ +
+ + # 01 is different to 1
+ + $c = (length($a) <=> length($b));
+ + return $c if ($c);
+ +
+ + $c = ($a cmp $b);
+ + return $c if ($c);
+ + }
+ + }
+ +
+ + return 1 if (@listA);
+ + return -1 if (@listB);
+ +
+ + return 0;
+ +}
+ +
+ sub linkpage ($) {
+ my $link=shift;
+ my $chars = defined $config{wiki_file_chars} ? $config{wiki_file_chars} : "-[:alnum:]+/.:_";
+ diff --git a/IkiWiki/Plugin/brokenlinks.pm b/IkiWiki/Plugin/brokenlinks.pm
+ index 37752dd..ccaa399 100644
+ --- a/IkiWiki/Plugin/brokenlinks.pm
+ +++ b/IkiWiki/Plugin/brokenlinks.pm
+ @@ -59,7 +59,7 @@ sub preprocess (@) {
+ map {
+ "<li>$_</li>"
+ }
+ - sort @broken)
+ + sort titlecmp @broken)
+ ."</ul>\n";
+ }
+
+ diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm
+ index 8efef3f..263e7a6 100644
+ --- a/IkiWiki/Plugin/inline.pm
+ +++ b/IkiWiki/Plugin/inline.pm
+ @@ -192,7 +192,7 @@ sub preprocess_inline (@) {
+ }
+
+ if (exists $params{sort} && $params{sort} eq 'title') {
+ - @list=sort { pagetitle(basename($a)) cmp pagetitle(basename($b)) } @list;
+ + @list=sort { titlecmp(pagetitle(basename($a)),pagetitle(basename($b))) } @list;
+ }
+ elsif (exists $params{sort} && $params{sort} eq 'mtime') {
+ @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list;
+ diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm
+ index b910758..10a1d87 100644
+ --- a/IkiWiki/Plugin/orphans.pm
+ +++ b/IkiWiki/Plugin/orphans.pm
+ @@ -56,7 +56,7 @@ sub preprocess (@) {
+ htmllink($params{page}, $params{destpage}, $_,
+ noimageinline => 1).
+ "</li>"
+ - } sort @orphans).
+ + } sort titlecmp @orphans).
+ "</ul>\n";
+ }
+
+ diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
+ index ceb7c84..00798e1 100644
+ --- a/IkiWiki/Render.pm
+ +++ b/IkiWiki/Render.pm
+ @@ -89,7 +89,7 @@ sub genpage ($$) {
+ $template->param(have_actions => 1);
+ }
+
+ - my @backlinks=sort { $a->{page} cmp $b->{page} } backlinks($page);
+ + my @backlinks=sort { titlecmp($a->{page}, $b->{page}) } backlinks($page);
+ my ($backlinks, $more_backlinks);
+ if (@backlinks <= $config{numbacklinks} || ! $config{numbacklinks}) {
+ $backlinks=\@backlinks;
--- /dev/null
+If RSS and Atom are enabled by default, the [[plugins/contrib/comments]]
+plugin generates a feed, perhaps `/sandbox/index.atom` for comments on the
+sandbox. If a blog is added to the page, the blog will steal the name
+`/sandbox/index.atom` and the comments plugin's feed will change to
+`/sandbox/index.atom2`.
+
+If `\[[!inline]]` gained a parameter `feedname` or something, the comments
+plugin could use `feedname=comments` to produce `/sandbox/comments.atom`
+instead (this would just require minor enhancements to rsspage(),
+atompage() and targetpage()).
+
+As a side benefit, [my blog](http://smcv.pseudorandom.co.uk/) could go back
+to its historical Atom feed URL of `.../feed.atom` (which is currently a
+symlink to `index.atom` :-) )
+
+On sites not using `usedirs` the current feed is `/sandbox.atom`, and we
+could perhaps change it to `/sandbox-comments.atom` or
+`/sandbox/comments.atom` if `feedname=comments` is given.
+
+--[[smcv]]
+
+> This is slightly hard to do, because you have to worry about
+> conflicting pages setting feedname, which could cause ikiwiki to blow up.
+>
+> Particularly for the non-usedirs case, where a page `sandbox/comments`
+> would produce the same feed as sandbox with `feedname=comments`.
+> --[[Joey]]
+
+> [[done]] as feedfile option --[[Joey]]
--- /dev/null
+ < joeyh> 03:49:19> also, I think it may be less visually confusing to
+ drop the rss/atom buttons for comments when there are none yet
+
+This seems to me like something that applies to the [[plugins/inline]] plugin in general, rather than the [[plugins/contrib/comments]] plugin specifically. --[[smcv]]
+
+>> [[done]] as emptyfeeds option, not on by default for inline, but I think
+>> it should be for comments --[[Joey]]
--- /dev/null
+[[!template id=gitbranch branch=smcv/ready/inline-pagenames author="[[smcv]]"]]
+
+A [[!taglink patch]] in my git repository (the inline-pagenames branch) adds
+the following parameter to the [[ikiwiki/directive/inline]] directive:
+
+> * `pagenames` - If given instead of `pages`, this is interpreted as a
+> space-separated list of links to pages (with the same
+> [[ikiwiki/SubPage/LinkingRules]] as in a [[ikiwiki/WikiLink]]), and they are inlined
+> in exactly the order given: the `sort` and `pages` parameters cannot be used
+> in conjunction with this one.
+
+This is on my [[wishlist]] for my [[plugins/contrib/album]] plugin, which currently
+uses it internally (as it has already collected the pages in order). It could also
+be useful for other things, like [[todo/wikitrails]]. --[[smcv]]
+
+[[!tag plugins/inline]]
+
+> It's sort of a pity that a pagespec like "a or b or c" doesn't somehow
+> match to (a, b, c) in that order, but I don't see how that would be
+> generally possible. While this feels a bit like bloat and inline already
+> has far too many parameters, I have [[merged|done]] it. --[[Joey]]
--- /dev/null
+[[!tag wishlist patch plugins/inline]]
+[[!template id=gitbranch branch=chrysn/patches author="[[chrysn]]"]]
+
+for postforms in inlines of pages which follow a certain scheme, it might not
+be required to set the title for each individual post, but to automatically set
+the title and show no input box prompting for it.
+this can either be based on timestamp formatting, or use the already existing
+munging mechanism, which appends numbers to page titles in case that page
+already exists.
+
+two patches ([1], [2]) set inline up for that, adding an additional `autotitle`
+parameter. if that is given, the regular input of the inline postform will be
+replaced with a hidden input of that text. in addition, the empty title is
+permitted (both for autotitle and regular titles, as they go in the same GET
+parameter, `title`). as the empty page title is illegal, munging is used,
+resulting in ascending numeric page titles to be created.
+
+the second patch is actually a one-liner, filtering the title through strftime.
+
+> Something similar was requested in [[todo/more_customisable_titlepage_function]],
+> in which [[Joey]] outlined a similar solution.
+>
+> What's your use-case for not prompting for the title at all? I can see
+> [[madduck]]'s requirement for the title he typed in (say, "foo")
+> being transformed into 2009/07/26/foo or something (I name blog posts
+> like that myself), but I can't quite see the use for *entirely* automatic
+> titles.
+>
+> However, if that's really what you want, I suspect your code could be
+> extended so it also solves madduck's second request on
+> [[todo/more_customisable_titlepage_function]].
+>
+> --[[smcv]]
+
+### potential user interaction issues
+
+this has two side effects which have to be considered: first, the empty page
+title is accepted also in normal postforms (previously, this resulted in a "bad
+page name" error); second, entering a percent sign in that field might result
+in unexpexted strftime substitution (strftime might not even substitute for
+common uses of percent as in "reach 10% market share", but might in others as
+in "the 10%-rule").
+
+both can be circumvented by using another GET parameter for autotexts, as
+implemented in [3].
+> this patch still does not work perfectly; especially, it should make a
+> distinction between "autotitle is set but equal ''" (in which case it
+> should create a page named `1.mdwn`, and "autotitle is not set, and title is
+> equal ''" (in which case it should display the old error message) --[[chrysn]]
+
+### potential security issues
+
+* the autotitle's value is directly output through the template (but that's
+ done in other places as well, so i assume it's safe)
+* i don't know if anything bad can happen if unfiltered content is passed to
+ POSIX::strftime.
+
+### further extension
+
+having a pre-filled input field instead of an unchangable hidden input might be
+cool (eg for creating an entry with yesterday's date), but would be a bit of a
+problem with static pages. javascript could help with the date part, but name
+munging would be yet another thing.
+
+[1]: http://github.com/github076986099/ikiwiki/commit/b568eb257a3ef5ff49a84ac00a3a7465b643c1e1
+[2]: http://github.com/github076986099/ikiwiki/commit/34bc82f232be141edf036d35e8ef5aa289415072
+[3]: http://github.com/github076986099/ikiwiki/commit/40dc10a4ec7809e401b4497c2abccfba30f7a2af
--- /dev/null
+[[!tag wishlist]]
+
+Continuing the ideas in [[bugs/Inline doesn't wikilink to pages]].
+
+I thought of a use case for another feature: making [[ikiwiki/directive/inline]] inherit the link relations of the included pages (optionally, say, with `inheritlinks=yes`). For example, if I want to list `elements/*` that have been linked to in any of `new_stuff/*`, I could try to write a [[ikiwiki/pagespec]] like
+`elements/* and backlink(new_stuff/*)`.
+
+This is not yet possible, as discussed in [[todo/tracking_bugs_with_dependencies]].
+
+It would be possible to work around this limitation of pagespecs if it was possible to create a page `all_new_stuff` with `\[[!inline pages="new_stuff/*" inheritlinks=yes]]`: then the desired pagespec would be expressed as `elements/* and backlink(all_new_stuff)`.
+
+> Or, instead of specifying whether to inherit at the place of the inline, add more relations (`inline`, `backinline`) and relation composition (say, `*`, or haskell-ish `$` in order not confuse with the glob `*`) and explicitly write in the pagespecs that you want to follow the inline relation backwards: `elements/* and backlink$backinline(all_new_stuff)` or, equivalently, if [["classes"|todo/tracking_bugs_with_dependencies]] are implemented in pagespecs: `elements/* and backlink(backinline(all_new_stuff))`. Of course, this suggestion requires the powerful extension to pagespecs, but it gives more flexibility, and the possibility to avoid redundant information: the same pagespec at two places -- the inline and the other matching construction.
+>
+> BTW, adding more relations -- the `inline` relation among them -- would satisfy [[the other feature request|bugs/Inline doesn't wikilink to pages]]. --Ivan Z.
+
+This is not just an ugly workaround. The availability of this feature has some reason: the classes of pages you want to refer to "recursively" (in that kind of complex pagespecs) tend to have some meaning themselves. So, I might indeed want to have a page like `all_new_stuff`, it would be useful for me. And at the same time I would like to write pagespecs like `elements/* and backlink(all_new_stuff)` -- and using the proposed feature in [[todo/tracking_bugs_with_dependencies/]] would be less clean because then I would have to enter the same information at two places: the possibly complex pagespec in the inline. And having redundant information leads to inconsistency.
+
+So in a sense, in some or most cases, it would indeed be cleaner to "store" the definition of a class of pages referred to in complex pagespecs as a separate object. And the most natural representation for this definition of a class of pages (adhering to the principle of wiki that what you mean is entered/stored in its most natural representation, not through some hidden disconnected code) is making a page with an inline/map/or the like, so that at the same time you store the definition and you see what it is (the set of pages is displayed to you).
+
+I would actually use it in my current "project" in ikiwiki: I actually edit a set of materials as a set of subpages `new_stuff/*`, and I also want to have a combined view of all of them (made through inline), and at another page, I want to list what has been linked to in `new_stuff/*` and what hasn't been linked to.--Ivan Z.
+
+> I see where you're coming from, but let's think about
+> immplementation efficiency for a second.
+>
+> In order for inline inheritlinks=yes to work,
+> the inline directive would need to be processed
+> during the scan pass.
+>
+> When the directive was processed there, it would need
+> to determine which pages get inlined (itself a moderatly
+> expensive operation), and then determine which pages
+> each of them link to. Since the scan pass is unordered,
+> those pages may not have themselves been scanned yet.
+> So to tell what they link to, inline would have to load
+> each of them, and scan them.
+>
+> So there's the potential for this to slow
+> down a wiki build by about a factor of 2.
+> --[[Joey]]
--- /dev/null
+This is a fleshed out todo based on discussions at
+[[forum/managing_todo_lists]].
+
+I would like to have TODO lists inside ikiwiki wikis. This would mean:
+
+* a new markup plugin to support a language suitable for TODO lists (OPML,
+ XOXO are two possible candidates)
+* some javascript to provide interactive editing.
+
+As [[chrysn]] pointed out on the forum page, this has some crossover with
+[[structured page data]]. In particular, if the markup language chosen had a
+concept of invalid markup (existing plugins just tend to ignore stuff that
+isn't explicitly part of their markup) we would need to sensibly handle that.
+Perhaps rejecting web edits and providing context help on why the edit was
+rejected, although that sounds like a significant headache.
+
+I have started working on this, albeit slowly. A proof of concept is at
+<http://dev.jmtd.net/outliner/>.
+
+There are two git repositories associated with my WIP: one contains the
+javascript, the plugin, the changes made to page templates; the other contains
+the contents of that wiki-site (so the test todos and the contents of bugs/
+which forms a sort-of todo list for the todo list :) ) I will endeavour to get
+mirrors of those repos up on github or similar asap.
+
+-- [[Jon]]
+
+----
+
+Just to report the WIP plugin for this is now in a reasonably good state. I ended
+up just inventing a new markup language -- for now, items are divided by newlines
+and lists are one-dimensional, for simplicity. I got fed up thinking about how to
+handle the structured data issues / needing a lot of boilerplate around items and
+the implications for the "new item" dialogue.
+
+Still quite a lot to do though!
+
+-- [[Jon]]
+
+I've pushed a copy of the work in progress which consists of
+
+ * A change to page.tmpl
+ * A javascript underlay directory + javascript file
+ * a few CSS bits in a local.css
+ * a plugin
+
+to <http://github.com/jmtd/ikiwiki_todolist/>
+
+-- [[Jon]]
+ikiwiki should be fully internationalized.
+
+----
+
+As to the hardcoded strings in ikiwiki, I've internationalized the program,
+and there is a po/ikiwiki.pot in the source that can be translated.
+--[[Joey]]
+
+----
+
+> The now merged po plugin handles l10n of wiki pages. The only missing
+> piece now is l10n of the templates.
+> --[[Joey]]
+
+----
+
From [[Recai]]:
> Here is my initial work on ikiwiki l10n infrastructure (I'm sending it
> before finalizing, there may be errors).
This could be easily worked around in tmpl_process3, but I wouldn't like to
maintain a separate utility.
-----
-
-As to the hardcoded strings in ikiwiki, I've internationalized the program,
-and there is a po/ikiwiki.pot in the source that can be translated.
---[[Joey]]
-
-----
-
-Danish l10n of templates and basewiki is available with the following commands:
-
- git clone http://source.jones.dk/ikiwiki.git newsite
- cd newsite
- make
-
-Updates are retrieved with this single command:
-
- make
-
-Right now the l10n is maintained by manually comparing against each new upstream release, and
-updating both the master mirror and the l10n as needed.
-
-Work is in progress to semi-automate this to still check manually for updates, but maintain the
-l10n as PO files - to allow more translations to more than the few languages I know about myself.
-
-As upstream ikiwiki is now maintained in GIT too, keeping the master mirror in sync with upstream
-could probably be automated even more - but an obstacle seems to be that content is not maintained
-separately but as an integral part of upstream source (GIT seems to not support subscribing to
-only parts of a repository).
-
-For example use, here's how to roll out a clone of the [Redpill support site](http://support.redpill.dk/):
-
- mkdir -p ~/private_webdata
- git clone http://source.redpill.dk/support.git ~/private_webdata/support.redpill.dk
- cd ~/private_webdata/support.redpill.dk
- make
- mkdir -p ~/public_websites/support.redpill.dk
- mkdir -p ~/public_websites/source.redpill.dk/support_content.git/hooks
- mkdir -p ~/public_cgi/support.redpill.dk
- make install
-
-(Redpill support is inspired by <http://help.riseup.net> but needs to be reusable for several similarly configured networks)
-
---[[JonasSmedegaard]]
Here is a patch for the [[plugins/meta]] plugin. It adds the possibility to define the language
-used for a page, with \[[meta lang="ja"]]
+used for a page, with \[[!meta lang="ja"]]
It doesn't insert the langage information in the xhtml meta elements, but defines a LANG
variable to use in the templates, for example with
my %authorurl;
+my %lang;
- sub import { #{{{
+ sub import {
hook(type => "preprocess", id => "meta", call => \&preprocess, scan => 1);
@@ -100,6 +101,11 @@
$meta{$page}.='<link href="'.encode_entities($value).
+ $template->param(lang => $lang{$page})
+ if exists $lang{$page} && $template->query(name => "lang");
- } # }}}
+ }
</pre>
> Please resolve lang somewhere reusable rather than within meta plugin: It is certainly usable outside
> the scope of the meta plugin as well. --[[JonasSmedegaard]]
-[[tag wishlist patch plugins/meta translation]]
+>> I don't see any problem with having this in meta? meta is on by default, and
+>> other plugins are free to use it or even depend on it (e.g. inline does).
+>>
+>> My only comments on this patch beyond what Joey said are that the page
+>> language could usefully go into `$pagestate{$page}{meta}{lang}` for other
+>> plugins to be able to see it (is that what you meant?), and that
+>> restricting to 2 characters is too restrictive (HTML 4.01 mentions
+>> `en`, `en-US` and `i-navajo` as possible language codes).
+>> This slightly complicates parsing the locale to get the default language:
+>> it'll need `tr/_/-/` after the optional `.encoding` is removed.
+>> --[[smcv]]
+
+>>> Now that po has been merged, this patch should probably also be adapted
+>>> so that the po plugin forces the meta::lang of every page to what po
+>>> thinks it should be. Perhaps [[the_special_po_pagespecs|ikiwiki/pagespec/po]]
+>>> should also work with meta-assigned languages? --[[smcv]]
+
+[[!tag wishlist patch plugins/meta translation]]
How about a plugin adding a
-[[preprocessor_directive|ikiwiki/preprocessordirective]] to render some given LaTeX
+[[preprocessor_directive|ikiwiki/directive]] to render some given LaTeX
and include it in the page? This could either render the LaTeX as a PNG via
-[[debpkg dvipng]] and include the resulting image in the page, or perhaps
+[[!debpkg dvipng]] and include the resulting image in the page, or perhaps
render via [HeVeA](http://pauillac.inria.fr/~maranget/hevea/index.html),
[TeX2page](http://www.ccs.neu.edu/~dorai/tex2page/tex2page-doc.html), or
similar. Useful for mathematics, as well as for stuff like the LaTeX version
of the ikiwiki [[/logo]].
+> [[users/JasonBlevins]] has also a plugin for including [[LaTeX]] expressions (by means of `itex2MML`) -- [[plugins/mdwn_itex]] (look at his page for the link). --Ivan Z.
+
----
ikiwiki could also support LaTeX as a document type, again rendering to HTML.
+> [[users/JasonBlevins]] has also a [[plugins/pandoc]] plugin (look at his page for the link): in principle, [Pandoc](http://johnmacfarlane.net/pandoc/) can read and write [[LaTeX]]. --Ivan Z.
+
----
Conversely, how about adding a plugin to support exporting to LaTeX?
>>> Have a look at [pandoc](http://code.google.com/p/pandoc/). It can make PDFs via pdflatex. --[[roktas]]
+>>>> Interesting, just yesterday I was playing with pandoc to make PDFs from my Markdown. Could someone advise me on how to embed these PDFs into ikiwiki? I need some guidance in implementing this. --[[JosephTurian]]
+
+>>>> [[users/JasonBlevins]] has a [[plugins/pandoc]] plugin (look at his page for the link). --Ivan Z.
+
----
[here](http://ng.l4x.org/gitweb/gitweb.cgi?p=ikiwiki.git/.git;a=blob;f=IkiWiki/Plugin/latex.pm) is a first stab at
a latex plugin. Examples [here](http://ng.l4x.org/latex/). Currently without image support for hevea. And the latex2html
output has the wrong charset and no command line switch to change that. Dreamland.
+As this link is not working, I setted a mirror here: <a href="http://satangoss.sarava.org/ikiwiki/latex.pm">http://satangoss.sarava.org/ikiwiki/latex.pm</a>.
+
+
----
Okay, now is the time for a mid term report i think.
> I'm thinking about renameing the preprocessor directive to teximg.
-> \[[teximg code="" alt="foo"]] makes sense.. Would it make sense to rename
+> \[[!teximg code="" alt="foo"]] makes sense.. Would it make sense to rename
> the whole plugin, or do you think that other tex stuff should go in this
> same plugin?
>
> --[[Joey]]
-[[tag soc]]
-[[tag wishlist]]
+[[!tag soc]]
+[[!tag wishlist]]
--[[madduck]]
-[[tag wishlist]]
+[[!tag wishlist]]
--[[madduck]]
-[[tag wishlist]]
+[[!tag wishlist]]
[[wikilinks|ikiwiki/wikilink]] could use that title by default when linking
to the page. That would allow pages to have a simple, easily linkable name
(without spaces, for instance), but use the proper title for links. For
-example, [[ikiwiki/PreprocessorDirective]] could use the `linktitle`
+example, [[ikiwiki/Directive]] could use the `linktitle`
"preprocessor directive", and pages for [[users]] could have `linktitle`s
that put spaces in their names.
Ideally, perhaps two versions of the title could exist, one for general
use, and an optional one for if the case in the actual link starts with an
-uppercase letter. That would allow [[ikiwiki/preprocessordirective]] to
+uppercase letter. That would allow [[ikiwiki/directive]] to
use the link text "preprocessor directive", but
-[[ikiwiki/PreprocessorDirective]] to use the link text "Preprocessor
+[[ikiwiki/Directive]] to use the link text "Preprocessor
Directive", for use at the beginnings of sentences. If the second version
did not exist, the first version would apply to both cases. However, that
also seems like potential overkill, and less important than the basic
--- /dev/null
+Would it be possible to make the installation location for the external
+plugins (those talked to via xmlrpc) configurable? Currently, they are
+installed into (and later expected to be in) /usr/lib/ikiwiki/plugins. For
+the Fedora package (which I maintain), I move them to
+/usr/libexec/ikiwiki/plugins. While not covered by the FHS, this seems to
+be a more appropriate place, see:
+https://fedoraproject.org/wiki/Packaging/Guidelines#Libexecdir.
+
+> This would need to be a build time configuration setting so the directory
+> is built into ikiwiki for use at runtime. --[[Joey]]
+
+As a side note, the accompanying proxy.py might better be placed into some directory on the python path.
+
+> If someone can show how to do so without needing a Setup.py and all the
+> pain that using one entails.. --[[Joey]]
+
+>> At the very least I don't think proxy.py should be on the `sys.path`
+>> under its current name. If it was renamed to ikiwiki_proxy or some such,
+>> possibly; but I think it's more appropriate to have it in an
+>> ikiwiki-specific directory (a "private module") since it's not useful for
+>> anything outside ikiwiki, and putting it in the same directory as the
+>> external plugins means it's automatically in their `sys.path` without
+>> needing special configuration. --[[smcv]]
+>> (a mostly-inactive member of Debian's Python modules packaging team)
--- /dev/null
+The `ikiwiki-w3m.cgi` script is installed (hard-coded) into `/usr/lib/w3m/cgi-bin`. On Fedora however, the w3m package expects it in `/usr/libexec/w3m/cgi-bin`. So, it would be nice if the destination for this script could be configured.
+
+> You can use `W3M_CGI_BIN now`. [[done]] --[[Joey]]
--- /dev/null
+[[!tag wishlist]]
+
+As noted in [[todo/tag_pagespec_function]], there is a "misbehavior" of a `tagged()` pagespec: it matches even pages which have plain links to the tag page.
+
+And in general, it would be quite useful to be able to distinguish different kinds of links: one more kind, in addition to "tag", is "bug dependency" noted in [[todo/structured_page_data#another_kind_of_links]] and [[todo/tracking_bugs_with_dependencies#another_kind_of_links]].
+
+It could distinguish the links by the `rel=` attribute. ([[Tags already receive a special rel-class|todo/rel_attribute_for_links]].) This means there is a general need for a syntax to specify user-defined rel-classes on wikilink (then bug deps would simply use their special rel-class, either directly, or through a special directive like `\[[!depends ]]`), and to refer to them in pagespecs (in forward and backward direction).
+
+Besides pagespecs, the `rel=` attribute could be used for styles. --Ivan Z.
+
+> FWIW, the `add_link` function introduced in a recent
+> release adds an abstraction that could be used to get
+> part of the way there to storing data about different types of
+> links. That function could easily be extended to take an optional
+> third parameter specifying the link type.
+>
+> Then there's the question of how to store and access the data. `%links`
+> does not offer a good way to add additional information about links.
+> Now, we could toss `%links` entirely and switch to an accessor function,
+> but let's think about not doing that..
+>
+> The data that seems to be needed is basically a deep hash, so
+> one could check `$linktype{$page}{tag}{$link}` to see if
+> the page contains a link of the given type. (Note that pages could
+> contain links that were duplicates except for their types.)
+>
+> There would be some data duplication, unfortuantly, but if `%linktype`
+> is not populated for regular wikilinks, it would at least be limited to
+> tags and other unusual link types, so not too bad.
+>
+> `%linktype` could be stored in `%pagestate`.. if so
+> the actual use might look like `$pagestate{$page}{linktype}{tag}{$link}`.
+> That could be implemented by the tag plugin right now
+> with no core changes. (BTW, then I originally wrote tag, pagestate
+> was not available, which is why I didn't make it differentiate from
+> normal links.) Might be better to go ahead and add the variable to
+> core though. --[[Joey]]
+
+I saw somewhere else here some suggestions for the wiki-syntax for specifying the relation name of a link. One more suggestion---[the syntax used in Semantic MediaWiki](http://en.wikipedia.org/wiki/Semantic_MediaWiki#Basic_usage), like this:
+
+<pre>
+... the capital city is \[[Has capital::Berlin]] ...
+</pre>
+
+So a part of the effect of [[`\[[!taglink TAG\]\]`|plugins/tag]] could be represented as something like `\[[tag::TAG]]` or (more understandable relation name in what concerns the direction) `\[[tagged::TAG]]`.
+
+I don't have any opinion on this syntax (whether it's good or not)...--Ivan Z.
--- /dev/null
+I'd like to be able to drop an unmodified RFC2822 email message into ikiwiki, and get it formatted to HTML. Something like this: <http://lwn.net/Articles/287056/>
+
+> We're discussing doing just that (well, whole mailboxes, really) over in
+> [[comment_by_mail]] --[[Joey]]
+>> The
+>> [[plugins/contrib/mailbox]]
+>> plugin is roughly feature complete at this point. It can read mbox, maildir, and
+>> MH folders, does threading, and deals with MIME (now with
+>> pagespec based sanity checking). No doubt lots of things could be
+>> be improved, and it hasn't been tested a great deal. Formatting of the body could be attempted
+>> as well. -- [[DavidBremner]]
+>>> One hitch I noticed was that it is not currently possible to treat a maildir
+>>> or an MH directory as a page (i.e. just call it foo.mh and have it transformed
+>>> to page foo). I'm not sure if this is possible and worthwhile to fix.
+>> It is certainly workable
+>>> to use a \[[!mailbox ]] directive. -- [[DavidBremner]]
+
+[[done]]
--- /dev/null
+The [StackOverflow](http://stackoverflow.com/) site uses markdown for markup.
+It has a fancy javascript thing for showing a real-time preview of what the user
+is editing. It would be nice if ikiwiki could support this, too. The thing they
+use on StackOverflow is supposed to be free software, so it should be easy to
+add to ikiwiki.
+
+> See [[wikiwyg]]. Note that I do not have a copy of the code for that, or
+> it'd be in ikiwiki already. --[[Joey]]
+
+>> I just had a brief look at the [[wikiwyg]] page and the link to the plugin was
+>> broken. The StackOverflow site uses the [WMD](http://wmd-editor.com/) editor,
+>> which seems to be related to the [ShowDown](http://attacklab.net/showdown/)
+>> javascript port of Markdown. Interestingly, [WMD source](http://wmd.googlecode.com/)
+>> is now available under an MIT license, though it is supposedly undergoing heavy
+>> refactoring. It looks like there was previous discussion ( [[todo/Add_showdown_GUI_input__47__edit]] )
+>> about a showdown plugin. Maybe a WMD plugin would be worthwhile. I might
+>> look into it if I have time on the weekend. -- [[Will]]
+
+[[!tag wishlist]]
+
+>>> Below is a simple plugin/[[patch]] to make use of the WMD editor.
+
+>>>> Now added to ikiwiki, thanks! --[[Joey]]
+
+>>> Turns out it isn't hard at all to
+>>> get a basic version going (which doesn't handle directives at all, nor does it swtich itself off when you're
+>>> editing something other than Markdown source). I've
+>>> removed the done tag so this is visible as a patch. -- [[Will]]
+
+>>>> Hmm, it would be good if it turned off for !mdwn. Although this could
+>>>> be difficult for a new page, since there is a dropdown selector to
+>>>> choose the markup language then. But it should be doable for editing an
+>>>> existing page.
+
+>>>>> I agree. I'm working on this for for both new pages and existing pages.
+>>>>> It shouldn't be hard once I get WMD going through the javascript API.
+>>>>> At the moment that is inexplicably failing, and I haven't had time to have a good look at why.
+>>>>> I may not get a chance to look at this again for a few weeks.
+
+>>>> Can I get a license statement (ie, GPL-2+) ffrom you for the plugin?
+>>>> --[[Joey]]
+
+>>>>> Certainly. You're free to use the code I posted below under the GPL-2+ license. You'll note
+>>>>> however that I haven't said anything about the WMD code itself. The WMD web page says:
+
+>>>>>> "I'm refactoring the code, and will be releasing WMD under the MIT license soon. For now you can download the most recent release (wmd-1.0.1.zip) and use it freely."
+
+>>>>> It might be best to contact <support@attacklab.net> to for an explicit license on that if you want to include it.
+>>>>> -- [[Will]]
+
+> So, I wonder if I should add a copy of the WMD source to ikiwiki, or rely
+> on the user or distribution providing it. It does not seem to be packaged
+> for Debian yet. Hmm, I also can't find any copyright or license info in
+> the zip file. --[[Joey]]
+
+>> This is a good question. My thought is that it will probably not be packaged any time soon,
+>> so you're better off adding it to IkiWiki. I'd contact the author of WMD and ask them. They
+>> may have more insight. -- [[Will]]
+
+Note that the WMD plugin does **not** handle directives. For this reason the normal `preview` button
+remains. Some CSS to clean up the display of the live WMD preview would be good.
+
+> Can you elucidate the CSS comment -- or will it be obvious what you mean
+> when I try it? Is it what's needed for the live preview? --[[Joey]]
+
+>> In the version of the plugin below, a new `div` is added just below the form. WMD
+>> populates this div with the HTML it generates from the Markdown source. This is not very
+>> pretty at the moment - it appears in the same place as the preview used to, but with no
+>> header or anything. Any standard IkiWiki preview will appear below the WMD live preview.
+>> I recommend having a look at <http://wmd-editor.com/examples/splitscreen>
+>> for what a little CSS could achieve. -- [[Will]]
+
+> Hmm, now that I've tried it, I notice that it does live preview by
+> default, below the edit window. Which is nice, but then if I hit the
+> preview button, I get two previews.. which is confusing. (Also, minor,
+> but: the live preview is missing the "Page Preview:" header.) --[[Joey]]
+
+> I wonder how annoying it would be to add some kind of simplistic wikilink
+> support to wmd's preview? And/or a wikilink button? While not supporting
+> directies is fine, not supporting wikilinks in a wiki seems a bit
+> lacking. It may also entice novide users to not use wikilinks and instead
+> use the hyperlinks that wmd does support. --[[Joey]]
+
+> Bug: When I preview, all the text in the edit field seems to be
+> converted from mdwn to html. I think that wmd is converting the mdwn
+> into html when the form is posted, so it would also save like that.
+> I assume that is designed for websites that do not use markdown
+> internally. Doesn't it have a setting to leave it as markdown?
+>> Found setting, fixed. --[[Joey]]
+
+>>> As I noted above, I've been working on the non-markdown page issue.
+>>> Below is my a new javascript file that I'm using, and below that a patch
+>>> to enable it. This patch makes the normal usage prettier - you get
+>>> a side panel with the live preview in it. It also adds a new config
+>>> option, `wmd_use101api`, which turns on code that tries to use the
+>>> wmd api. At the moment this code doesn't seem to work - moreover the
+>>> code that uses the new API dies early, so any code after that point is
+>>> completely untested. I will not
+>>> get a chance to look at this again soon though, so I thought I'd post
+>>> my progress so far. -- [[Will]]
+
+
+Place the following file in `underlays/wmd/wmd-ikiwiki.js`.
+
+----
+
+ // This is some code to interface the WMD interface 1.0.1 with IkiWiki
+ // The WMD interface is planned to change, so this file will likely need
+ // updating in future.
+
+ if (useWMDinterface) {
+ wmd_options = { autostart: false, output: "Markdown" };
+ var instance = null;
+
+ hook("onload", initwmd);
+ } else {
+ var typeSelector = document.getElementById("type");
+
+ var currentType = getType(typeSelector);
+
+ if (currentType == "mdwn") {
+ wmd_options = { output: "Markdown" };
+ document.getElementById("wmd-preview-container").style.display = 'none';
+ } else {
+ wmd_options = { autostart: false };
+ document.getElementById("wmd-preview-container").style.display = 'block';
+ }
+ }
+
+ function initwmd() {
+ if (!Attacklab || !Attacklab.wmd) {
+ alert("WMD hasn't finished loading!");
+ return;
+ }
+
+ var typeSelector = document.getElementById("type");
+
+ var currentType = getType(typeSelector);
+
+ if (currentType == "mdwn") {
+ window.setTimeout(enableWMD,10);
+ }
+
+ typeSelector.onchange=function() {
+ var docType=getType(this);
+
+ if (docType=="mdwn") {
+ enableWMD();
+ } else {
+ disableWMD();
+ }
+ }
+ }
+
+ function getType(typeSelector)
+ {
+ if (typeSelector.nodeName.toLowerCase() == 'input') {
+ return typeSelector.getAttribute('value');
+ } else if (typeSelector.nodeName.toLowerCase() == 'select') {
+ return typeSelector.value;
+ // return typeSelector.options[typeSelector.selectedIndex].innerText;
+ }
+ return "";
+ }
+
+ function enableWMD()
+ {
+ var editContent = document.getElementById("editcontent");
+ var previewDiv = document.getElementById("wmd-preview");
+ var previewDivContainer = document.getElementById("wmd-preview-container");
+
+ previewDivContainer.style.display = 'block';
+ // editContent.style.width = previewDivContainer.style.width;
+
+ /***** build the preview manager *****/
+ var panes = {input:editContent, preview:previewDiv, output:null};
+ var previewManager = new Attacklab.wmd.previewManager(panes);
+
+ /***** build the editor and tell it to refresh the preview after commands *****/
+ var editor = new Attacklab.wmd.editor(editContent,previewManager.refresh);
+
+ // save everything so we can destroy it all later
+ instance = {ta:editContent, div:previewDiv, ed:editor, pm:previewManager};
+ }
+
+ function disableWMD()
+ {
+ document.getElementById("wmd-preview-container").style.display = 'none';
+
+ if (instance != null) {
+ instance.pm.destroy();
+ instance.ed.destroy();
+ // inst.ta.style.width='100%'
+ }
+ instance = null;
+ }
+
+
+----
+
+ diff --git a/IkiWiki/Plugin/wmd.pm b/IkiWiki/Plugin/wmd.pm
+ index 9ddd237..743a0b8 100644
+ --- a/IkiWiki/Plugin/wmd.pm
+ +++ b/IkiWiki/Plugin/wmd.pm
+ @@ -17,6 +17,13 @@ sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ + rebuild => 1,
+ + },
+ + wmd_use101api => {
+ + type => "boolean",
+ + description => "Use the advanced, but unstable, WMD api for markdown preview.",
+ + safe => 0,
+ + rebuild => 0,
+ },
+ }
+
+ @@ -24,29 +31,25 @@ sub formbuilder_setup (@) {
+ my %params=@_;
+ my $form=$params{form};
+
+ - return if ! defined $form->field("do");
+ + return unless defined $form->field("do");
+
+ return unless $form->field("do") eq "edit" ||
+ - $form->field("do") eq "create" ||
+ - $form->field("do") eq "comment";
+ -
+ - $form->tmpl_param("wmd_preview", "<div class=\"wmd-preview\"></div>\n".
+ - include_javascript(undef, 1));
+ -}
+ -
+ -sub include_javascript ($;$) {
+ - my $page=shift;
+ - my $absolute=shift;
+ -
+ - my $wmdjs=urlto("wmd/wmd.js", $page, $absolute);
+ - return <<"EOF"
+ -<script type="text/javascript">
+ -wmd_options = {
+ - output: "Markdown"
+ -};
+ -</script>
+ -<script src="$wmdjs" type="text/javascript"></script>
+ -EOF
+ + $form->field("do") eq "create" ||
+ + $form->field("do") eq "comment";
+ +
+ + my $useAPI = $config{wmd_use101api}?'true':'false';
+ + my $ikiwikijs = urlto("ikiwiki.js", undef, 1);
+ + my $wmdIkiwikijs = urlto("wmd-ikiwiki.js", undef, 1);
+ + my $wmdjs = urlto("wmd.js", undef, 1);
+ +
+ + my $previewScripts = <<"EOS";
+ + <script type="text/javascript">useWMDinterface=$useAPI;</script>
+ + <script src="$ikiwikijs" type="text/javascript"></script>
+ + <script src="$wmdIkiwikijs" type="text/javascript"></script>
+ + <script src="$wmdjs" type="text/javascript"></script>
+ +EOS
+ +
+ + $form->tmpl_param("wmd_preview", $previewScripts);
+ }
+
+ 1
+ diff --git a/doc/style.css b/doc/style.css
+ index a6e6734..36c2b13
+ --- a/doc/style.css
+ +++ b/doc/style.css
+ @@ -76,9 +76,16 @@ div.tags {
+ float: right;
+ }
+
+ +/*
+ #editcontent {
+ width: 100%;
+ }
+ +*/
+ +
+ +#wmd-preview-container {
+ + width: 49%;
+ + float: right;
+ +}
+
+ img {
+ border-style: none;
+ diff --git a/templates/editpage.tmpl b/templates/editpage.tmpl
+ index b1cf015..1d2f080 100644
+ --- a/templates/editpage.tmpl
+ +++ b/templates/editpage.tmpl
+ @@ -15,6 +15,14 @@ Page type: <TMPL_VAR FIELD-TYPE>
+ <TMPL_VAR FIELD-PAGE>
+ <TMPL_VAR FIELD-TYPE>
+ </TMPL_IF>
+ +<TMPL_IF NAME="WMD_PREVIEW">
+ +<div id="wmd-preview-container">
+ +<div class="header">
+ +<span>Live preview:</span>
+ +</div>
+ +<div class="wmd-preview" id="wmd-preview"></div>
+ +</div>
+ +</TMPL_IF>
+ <TMPL_VAR FIELD-EDITCONTENT><br />
+ <TMPL_IF NAME="CAN_COMMIT">
+ Optional comment about this change:<br />
-* 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
passed through to mercurial -u. Will mercurial choke on this?
It seems that with the current mercurial commit code, it will always
blindly overwrite the current file with the web edited version, losing
any other changes.
+* `rcs_commit_staged`, `rcs_rename`, `rcs_remove`, and `rcs_diff` are not
+ implemented for mercurial, and so attachments, remove and rename plugins
+ and recentchangesdiff cannot be used with it. (These should be fairly
+ easy to add..)
Posthook: in `$srcdir/.hg/hgrc`, I have the following
> It can deadlock if the post-commit hook runs with --refresh in the
> former case. --[[Joey]]
+The problem with --post-commit is that if you delete some pages in $SRC, ikiwiki --setup setupfile --post-commit will not delete them in $DEST. --[[users/weakish]]
+
+> You should really be using a setup file that has `mercurial_wrapper`
+> set, and running the wrapper generated by that from your hook.
+> That will work. I think that the `--setup --post-commit` on the command
+> line is currently broken and does the same expensive rebuild process as --setup
+> alone (which doesn't delete files from $DEST either). Will fix that.
+> (fixed)
+> --[[Joey]]
+
+>> Mercurial doesn't support put hooks in .hg/hooks/* (like git). In Mercurial, the only way to run
+>> your own hooks is specifying them in the hgrc file. (Or write a new extension.)
+>> I guess use a very long command will work.
+>> (e.g. ikiwiki --post-commit --a-lot-of-switches --set var=value $SRC $DEST)
+>> (Fortunately ikiwiki supports --set var=value so without --setup works.)
+>>
+>> Alternative is always editing via cgi or pushing. Never work on the $SRC/repo directly.
+>> --[[users/weakish]]
+
+>>> I don't see anything preventing you from using a setup file with
+>>> `mercurial_wrapper => ".hg/ikiwiki-hook",` and then modifying the hgrc
+>>> to run that wrapper. --[[Joey]]
+
+>> Thanks for pointing out this. I have some stupid misunderstanding on the
+>> usage of mercurial_wrapper before. The wrapper works nicely! --[[weakish]]
+
+I add the following to .hg/hgrc:(I use changegroup since I don't think we need refresh per changeset, please point out if I am wrong.)
+
+ [hooks]
+ changegroup = hg update >&2 && ikiwiki --setup path.to.setup.file --refresh
+ post-commit = path.to.the.mercurial.wrapper
+
+-----
+
+I have no idea when the deadlock will happen. --[[users/weakish]]
+
+> For the deadlock to occur, a edit has to be made via the web.
+>
+> Ikiwiki,
+> running as a CGI, takes a lock on the wiki, and commits the edit,
+> continuing to run in the background, with the lock still held.
+> When the edit is committed, the hg hook runs, running `ikwiki --refresh`.
+> Nearly the first thing that process does it try to lock the wiki..
+> which is already locked. This lock is taken in a blocking manner,
+> thus the deadlock -- the cgi is waiting for the commit to finish before
+> dropping the lock, and the commit is blocked waiting for the lock to be
+> released.
+>
+> --post-commit avoids this problem by checking if the cgi is running
+> and avoiding doing anything in that case. (While still handing the
+> refresh if the commit was not made by the CGI.)
+> So in that case, the commit finishes w/o ikiwiki doing anything,
+> and the ikiwiki CGI handles the wiki refresh.
+> --[[Joey]]
+
+
***
I have a few notes on mercurial usage after trying it out for a while:
-The following patch adds an 'rcsid' parameter to the Meta plugin, to allow inclusion
+The following patch adds an 'rcsid' parameter to the [[!taglink plugins/Meta]] plugin, to allow inclusion
of CVS/SVN-style keywords (like '$Id$', etc.) from the source file in the page template.
> So the idea is you'd write something like:
>
-> \[[meta rcsid="$Id$"]]
+> \[[!meta rcsid="$Id$"]]
>
> And this would be put at the bottom of the page or somewhere like that by
> the template?
my %copyright;
+my %rcsid;
- sub import { #{{{
+ sub import {
hook(type => "preprocess", id => "meta", call => \&preprocess, scan => 1);
@@ -110,6 +111,9 @@
$meta{$page}.="<link rel=\"copyright\" href=\"#page_copyright\" />\n";
There should be a way to add metadata to a page. Probably a plugin could do
this, for example:
- \[[meta foo="bar"]]
+ \[[!meta foo="bar"]]
Uses for this include:
except it doesn't have to show up in the page text.
* Recording page licenses.
-[[meta link=done]]
-[[meta title="supporting metadata..."]]
-[[meta author="Joey Hess"]]
-[[meta link="foo.css" rel="stylesheet" type="text/css"]]
+[[!meta link=done]]
+[[!meta title="supporting metadata..."]]
+[[!meta author="Joey Hess"]]
+[[!meta link="foo.css" rel="stylesheet" type="text/css"]]
[[todo/done]]
# Allow generating feeds even if not generated by default?
#allowrss => 1,
-[[tag patch]]
+[[!tag patch]]
> Hmm, recentchanges is just a blog. Of course the word "blog" is perhaps
> being used in too broad a sense here, since it tends to imply personal
--- /dev/null
+I've got a wiki that is built at two places:
+
+* a static copy, aimed at being viewed without any web server, using
+ a web browser's `file:///` urls => usedirs is disabled to get nice
+ and working links
+* an online copy, with usedirs enabled in order to benefit from the
+ language negotiation using the po plugin
+
+I need to use mirrorlist on the static copy, so that one can easily
+reach the online, possibly updated, pages. But as documented, "pages are
+assumed to exist in the same location under the specified url on each
+mirror", so the generated urls are wrong.
+
+My `mirrorlist` branch contains a patch that allows one to configure usedirs
+per-mirror. Note: the old configuration format is still supported, so this should
+not break existing wikis.
+
+OT: as a bonus, this branch contains a patch to support {hashes,arrays} of
+{hashes,arrays} in `$config`, which I missed a bit when writing the po plugin,
+and decided this time it was really needed to implement this feature.
+
+--[[intrigeri]]
+
+[[!tag patch]]
something like this:
<pre>
-[[missingparents pages="posts/* and !posts/*/*" generate="""[[template id=year text="$page"]]"""]]
-[[missingparents pages="posts/*/* and !posts/*/*/*" generate="""[[template id=month text="$page"]]"""]]
-[[missingparents pages="posts/*/*/* and !posts/*/*/*/*" generate="""[[template id=day text="$page"]]"""]]
+[[!missingparents pages="posts/* and !posts/*/*" generate="""[[!template id=year text="$page"]]"""]]
+[[!missingparents pages="posts/*/* and !posts/*/*/*" generate="""[[!template id=month text="$page"]]"""]]
+[[!missingparents pages="posts/*/*/* and !posts/*/*/*/*" generate="""[[!template id=day text="$page"]]"""]]
</pre>
And it scans the whole wiki for pages that match the pagespecs but are missing
+my %ownfiles;
+my @pagespecs;
+
-+sub import { #{{{
++sub import {
+ hook(type => "checkconfig", id => "missingparents", call => \&checkconfig);
+ hook(type => "needsdelete", id => "missingparents", call => \&needsdelete);
+ hook(type => "needsbuild", id => "missingparents", call => \&needsbuild);
+ hook(type => "savestate", id => "missingparents", call => \&savestate);
+ hook(type => "preprocess", id => "missingparents", call => \&preprocess_missingparents);
-+} # }}}
++}
+
-+sub checkconfig () { #{{{
++sub checkconfig () {
+ IkiWiki::preprocess("missingparents", "missingparents",
+ readfile(srcfile("missingparents.mdwn")));
+ loadstate();
+ unlink $config{srcdir}.'/'.$file;
+ }
+ }
-+} #}}}
++}
+
-+sub preprocess_missingparents (@) { #{{{
++sub preprocess_missingparents (@) {
+ my %params=@_;
+
+ if (! defined $params{pages} || ! defined $params{generate}) {
-+ return "[[missingparents ".gettext("missing pages or generate parameter")."]]";
++ return "[[!missingparents ".gettext("missing pages or generate parameter")."]]";
+ }
+
+ push @pagespecs, \%params;
+ #translators: is text for pages that match that pagespec.
+ return sprintf(gettext("missingparents in %s will be %s"),
+ '`'.$params{pages}.'`', '`\\'.$params{generate}.'`');
-+} # }}}
++}
+
+my $state_loaded=0;
-+sub loadstate() { #{{{
++sub loadstate() {
+ my $filename = "$config{wikistatedir}/missingparents";
+ if (-e $filename) {
+ open (IN, $filename) ||
+
+ $state_loaded=1;
+ }
-+} #}}}
++}
+
-+sub savestate() { #{{{
++sub savestate() {
+ my $filename = "$config{wikistatedir}/missingparents.new";
+ my $cleanup = sub { unlink ($filename) };
+ open (OUT, ">$filename") || error("open $filename: $!", $cleanup);
+ }
+ rename($filename, "$config{wikistatedir}/missingparents") ||
+ error("rename $filename: $!", $cleanup);
-+} #}}}
++}
+
-+sub needsdelete (@) { #{{{
++sub needsdelete (@) {
+ my $files=shift;
+
+ my @mydel;
+ foreach my $page (@mydel){
+ push @{$files}, $page;
+ }
-+} #}}}
++}
+
-+sub check_matches($) { #{{{
++sub check_matches($) {
+ my $page = shift;
+ return if $IkiWiki::pagesources{$page};
+
+ return $output;
+ }
+ return "";
-+} #}}}
++}
+
-+sub needsbuild ($) { #{{{
++sub needsbuild ($) {
+ my $files=shift;
+ my @new;
+
+ $ownfiles{$file} = 1;
+ push @{$files}, $file;
+ }
-+} #}}}
++}
+
+1
Index: IkiWiki.pm
our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE
@@ -330,6 +336,30 @@
error("failed renaming $newfile to $destdir/$file: $!", $cleanup);
- } #}}}
+ }
-+sub newpage($$) { #{{{
++sub newpage($$) {
+ my $file=shift;
+ my $page=shift;
+
+ $pagemtime{$page} = $pagectime{$page} = time;
+ $pagesources{$page} = $file;
+ $pagecase{lc $page} = $page;
-+} #}}}
++}
+
-+sub delpage($) { #{{{
++sub delpage($) {
+ my $page=shift;
+ $links{$page}=[];
+ $renderedfiles{$page}=[];
+ delete $destsources{$_};
+ }
+ }
-+} #}}}
++}
+
my %cleared;
- sub will_render ($$;$) { #{{{
+ sub will_render ($$;$) {
my $page=shift;
</pre>
-[[tag patch]]
+[[!tag patch patch/core]]
--- /dev/null
+I'm writing a plugin to wikify c/c++ code.
+
+By default ikiwiki generates xxx.html for a file called xxx.c.
+
+The problem is that I occasionally have xxx.c and xxx.h in the same directory and there's a filename collision.
+
+My solution is to allow plugins to provide a hook that sets the pagename. --[[/users/bstpierre]]
+
+> You might also find the solution to [[bugs/multiple_pages_with_same_name]] helps you. That patch is already applied. -- [[Will]]
+
+ --- /usr/share/perl5/IkiWiki.pm.ORIG 2008-10-03 14:12:50.000000000 -0400
+ +++ /usr/share/perl5/IkiWiki.pm 2008-10-07 11:57:26.000000000 -0400
+ @@ -196,11 +196,32 @@
+
+ sub pagename ($) {
+ my $file=shift;
+
+ my $type=pagetype($file);
+ +
+ + if(defined $type &&
+ + exists $hooks{pagename} &&
+ + exists $hooks{pagename}{$type}) {
+ +
+ + return $hooks{pagename}{$type}{call}($file);
+ +
+ + } else {
+ +
+ my $page=$file;
+ $page=~s/\Q.$type\E*$// if defined $type;
+ return $page;
+ + }
+ }
+
+ sub htmlpage ($) {
+
> applied --[[Joey]]
+----
+
The following adds a div element with class="trailer" around the meta-information
added after an inlined page (namely: the post date, the tags, and the actions):
+
+</div>
-[[tag patch]]
+[[!tag patch]]
> Unfortunately, the inlinepage content passes through markdown, and markdown
> gets confused by these nested div's and puts p's around one of them, generating
> broken html. If you can come up with a way to put in the div that passes
> the test suite, or a fix to markdown, I will accept it, but the above patch
-> fails the test suite. --[[Joey]]
+> fails the test suite. --[[Joey]]
>> Just a note... This discrepancy doesn't exist in [pandoc](http://code.google.com/p/pandoc/) as
>> demonstrated in the relevant [page](http://code.google.com/p/pandoc/wiki/PandocVsMarkdownPl).
>> alternatives is always a good thing and perhaps, the fact that pandoc can make markdown->LaTeX
>> conversion may lead to new possibilities. --[[Roktas]]
->>> I confirm that this ([[debbug 405058]]) has just been fixed in markdown
+>>> I confirm that this ([[!debbug 405058]]) has just been fixed in markdown
>>> [`1.0.2b7`](http://packages.debian.org/experimental/web/markdown) (BTW, thanks to your bug
>>> report Joey). FYI, I've observed some performance drop with `1.0.2b7` compared to `1.0.1`,
>>> especially noticable with big files. This was also confirmed by someone else, for example,
>>>> to at least get into debian testing before I make ikiwiki depend on it
>>>> though. --[[Joey]]
+>> This Markdown issue seems to have been worked around by the optimization
+>> in which \[[!inline]] is replaced with a placeholder, and the
+>> placeholder is later replaced by the HTML. Meanwhile, this patch
+>> has been obsoleted by applying a similar one (wrapping things in a div
+>> with class inlinefooter). That was the last remaining unapplied patch
+>> on this page, so I think this whole page can be considered [[done]].
+>> --[[smcv]]
+
+----
+
I'd like a class attribute on the `<span>` tag surrounding wikilinks
that refer to non-existent pages, in Ikiwiki.pm:htmllink, so that such
broken links can be styled more dramatically with CSS. --Jamey
I imagine two things: a lookup hash and a template.
-Since `IkiWiki::titlepage` basically translates characters, it would be cool to be able to define a lookup hash in the configuration, which would be consulted before falling back to the generic `__xx__` `ord()` representation of a letter. For instance, in German, I might prefer to have 'Ã\83¤' become 'ae' instead of something illegible.
+Since `IkiWiki::titlepage` basically translates characters, it would be cool to be able to define a lookup hash in the configuration, which would be consulted before falling back to the generic `__xx__` `ord()` representation of a letter. For instance, in German, I might prefer to have 'ä' become 'ae' instead of something illegible.
+
+> This is [[todo/unaccent_url_instead_of_encoding]]. --[[smcv]]
Second, maybe a template could be honoured. The template could have a slot `%s` where the calculated title goes, and it could contain `strftime` symbols as well as variables, which get interpolated on use.
-- [[madduck]]
+> This somewhat resembles [[todo/inline_postform_autotitles]].
+> Another way to do this, suggested in that todo, would be to
+> pre-fill the title field with YYYY/MM/DD/ using Javascript.
+> --[[smcv]]
+
I don't think that changing titlepage is a good idea, there are
compatability problems.
confuse the user. The title could be passed on in a hidden field, and
prepended to the page when it's saved..
+--[[Joey]]
+
+> I'll pass on these comments to the two similar todo items. --[[smcv]]
+
[[wishlist]]
--- /dev/null
+Using the [[plugins/inline]] plugin, you can get an inline-postform for
+creating new pages.
+
+It would be quite nice to have the flexibility to do this outside of the
+inline directive.
+
+I've got a proof-of-concept hacked inline comment submission example at
+<http://dev.jmtd.net/comments/> for example. I've just copied the HTML from
+the post form and stuck it inside a [[plugins/toggle]].
+
+(Before Simon completed the comments plugin, I thought this would the a
+logical first step towards doing comment-like things with inlined pages).
+
+-- [[Jon]]
+
+> Perhaps what we need is a `postform` plugin/directive that inline depends
+> on (automatically enables); its preprocess method could automatically be
+> invoked from preprocess_inline when needed. --[[smcv]]
editing one of the html templates and rebuilding the wiki can change every
page. All of these need to be reflected in the file mtime to avoid caching
problems.
+
+[[!tag wishlist]]
--[[bma]]
-[[tag wishlist]]
+[[!tag wishlist]]
--- /dev/null
+I'd like to be able to use one git repository for my basic website, and
+another one for the big files (pictures, videos), and another one for temp
+files. This way I'd not bloat the basic repo, and I could toss temp files
+up, and throw the temp repo away periodically.
+
+For this to work really well, ikiwiki would need multiple repository
+support. Possibly it could be tied into 'mr'?
+
+Another thought is that it would be good if ikiwiki could determine the
+type of repo a subdirectory is in by itself, eliminating the need to
+manually configure it in the setup file.
+
+--[[Joey]]
+
+[[!tag wishlist]]
> Another useful feature might be to be able to choose a different [[template|wikitemplates]]
-> file for some pages; [[blog|ikiwiki/blog]] pages would use a template different from the
+> file for some pages; [[blog]] pages would use a template different from the
> home page, even if both are managed in the same repository, etc.
Well, that would probably be fairly easy to add if it used [[pagespecs|ikiwiki/pagespec]] to
--- /dev/null
+[[!tag wishlist]]
+[[!tag patch]]
+
+the inline plugin's sorting is plain lexical, thich may not be appropriate for
+page titles if they have numeric components. the
+[Sort::Naturally](http://search.cpan.org/dist/Sort-Naturally/) perl module
+provides an algorithm for that.
+
+there is a
+[patch](http://git.ikiwiki.info/?p=ikiwiki;a=commit;h=55b83cb7bd1cd7c60bb45dc22c3745dd80a63fed)
+attached that makes the [[plugins/inline]] plugin use Sort::Naturally if sort
+is set to "title_natural".
+
+the current patch uses `require Sort::Naturally`, so
+[libsort-naturally-perl](http://packages.debian.org/libsort-naturally-perl)
+does not become a dependency; it might be worth suggesting, though.
+
+> See also: [[inline:_numerical_ordering_by_title]] (I probably prefer your
+> approach..) --[[Joey]]
+
+> [[applied|done]]
--- /dev/null
+As documented in [[plugins/write]], the current `renamepage` hook is
+heavily oriented towards updating links in pages' content: it is run
+once per page linking to the renamed page.
+
+That's fine, but it can't be used to trigger more general actions on
+page rename. E.g. it won't be run at all if the page being renamed is
+an orphan one.
+
+This is a real issue for the [[plugins/contrib/po]] development: what
+I'm about to achieve is:
+
+- when a master page is renamed, the plugin takes notice of it (using
+ the `rename` hook), and later renames the translation pages
+ accordingly (in the `change` hook)
+- when a master page is deleted, the plugin deletes its translations
+ (using the `delete` hook)
+
+With the current `renamepage` hook behavior, combining these two goals
+has an annoying drawback: a plugin can't notice an orphan master page
+has been renamed, so instead of renaming (and preserving) its
+translations, it considers the oldpage as deleted, and deletes its
+translations. Game over.
+
+It may seem like a corner case, but I want to be very careful when
+deleting files automatically in `srcdir`, which is not always under
+version control.
+
+As a sad workaround, I can still disable any deletion in `srcdir`
+when it is not under version control. But I think ikiwiki deserves
+a global `renamepage` hook that would be run once per rename
+operation.
+
+My proposal is thus:
+
+- keep the documented `renamepage` hook as it is
+- use something inspired by the trick `preprocess` uses: when `hook`
+ is passed an optional "global" parameter, set to a true value, the
+ declared `renamepage` hook is run once per rename operation, and is
+ passed named parameters: `src`, `srcfile`, `dest` and `destfile`.
+
+I'm of course volunteering to implement this, or anything related that
+would solve my problem. Hmmm? --[[intrigeri]]
+
+> I think it would be better to have a different hook that is called for
+> renames, since the two hook actions are very different (unlike the
+> preprocess hook, which does a very similar thing in scan mode).
+>
+> Just calling it `rename` seems like a reasonable name, by analogy with
+> the `delete` and `change` hooks.
+>
+> It might make sense to rename `renamepage` to `renamelink` to make it
+> clearer what it does. (I'm not very worried about this breaking things, at
+> this point.) --[[Joey]]
+
+>> In my `po` branch, I renamed `renamepage` to `renamelink`, and
+>> created a `rename` hook that is passed a reference to `@torename`.
+>> --[[intrigeri]]
+
+>>> As Joey highlights it on [[plugins/contrib/po]], it's too late to
+>>> merge such a change, as the 3.x plugin API is released and should
+>>> not be broken. I will thus keep the existing `renamepage` as it
+>>> is, and call `rename` the global hook I need. --[[intrigeri]]
+
+>>>> [[Done]] in my `po` branch. --[[intrigeri]]
+
+I think I see a problem in the rename hook. The hook is called
+before the plugin adds any subpages to the set of pages to rename.
+So, if the user choses to rename subpages, po will not notice
+they are moving, and will not move their po files.
+
+Perhaps the hooks should be moved to come after subpages are added.
+This would, though, mean that if the hook somehow decides to add
+entirely other pages to the list, their subpages would not be
+automatically added.
+
+I also have some qualms about the design of the hook. In particular,
+passing the mutable array reference probably makes it impossible
+to use from external plugins. Instead it could return any additional
+rename hashes it wants to add. Or, if the ability to modify existing
+hashes is desired, it could return the full set of hashes.
+
+--[[Joey]]
+
+> I fixed the last part, i.e. a rename hook function now returns the
+> full set of hashes. As I also converted it to take named parameters,
+> such a function still is passed a reference to the original array,
+> though, because one can't build a hash containing an array of hashes
+> as a value, without passing this array as a reference.
+>
+>> Sure.
+>
+> I'm not entirely sure about your first concern. Calling the hook
+> before or after the subpages addition both have their own problems.
+>
+> What about running the hook before *and* after the subpages
+> addition, with an additional `when` named parameter, so that
+> a given hook function can choose to act only before or after, or both?
+>
+> --[[intrigeri]]
+>>
+>> Have you thought about making the hook be run once *per* file that is
+>> selected to be renamed? This would even handle the case where two
+>> plugins use the hook; plugin A would see when plugin B adds a new file
+>> to be renamed. And the subpage renaming stuff could probably be moved
+>> into the rename hook too. --[[Joey]]
+>>>
+>>> I've implemented this nice solution in my po branch, please review.
+>>> I'm slowly coming back to do the last bits needed to get my po and
+>>> meta branch merged. --[[intrigeri]]
+
+>>>> It looks good. I made some small changes to it in my own po branch.
+>>>> Nothing significant really. If this were not tied up in the po branch,
+>>>> I've have merged it to master already. --[[Joey]]
+
+>>>> Thanks, this is great :) --[[intrigeri]]
>
> For example, I *think* you can unambiguously parse the following:
>
-> \[[if test="enabled(template) and templates/foo" then="""
-> [[template id=foo content="""Flying Purple People Eater"""]]
+> \[[!if test="enabled(template) and templates/foo" then="""
+> [[!template id=foo content="""Flying Purple People Eater"""]]
> """]]
>
> --[[JoshTriplett]]
--- /dev/null
+It should be possible to configure ikiwiki online, in the wiki admin's
+preferences form. Rather than the current situation where most settings are
+in ikiwiki.setup, and one or two (like locked pages and upload limits) in
+the admin preferences.
+
+In theory, every setting could be configured there. In practice, some
+settings, like `srcdir` and `destdir` are ones you want to keep far away
+from editing via the web.
+
+The underlying work has been done to privide metadata about all options via
+getsetup hooks, so it's just a matter of writing a web interface plugin.
+
+The plugin could have these config options:
+
+ # list of options to include in web setup (safe = all things with safe = 1)
+ websetup_include => [qw{safe}],
+ # list of options to exclude from web setup
+ websetup_exclude => [qw{option_baz}],
+ # list of plugins that cannot be enabled/disabled via the web
+ # interface
+ websetup_force_plugins => [qw{git svn bzr mercurial monotone tla}]
+
+Leaning toward just making it write out to the same setup file, rather than
+writing to a subsidiary setup file. However, this would mean that any
+comments in the file would be lost, and that it couldn't be used if the
+setup file had weird stuff (perl code, etc).
+
+[[!tag wishlist done]]
* Look at splitting up CGI.pm. But note that too much splitting can slow
perl down.
+ > It's split enough, or possibly more than enough, now. :-)
+
* The backlinks calculation code is still O(N^2) on the number of pages.
If backlinks info were stored in the index file, it would go down to
constant time for iterative builds, though still N^2 for rebuilds.
+
+ > Seems to be O(Num Pages * Num Links in Page), or effectively O(N)
+ > pages for most wikis.
+
+[[done]]
--- /dev/null
+Some aggregators, like Planet, sort by mtime rather than ctime. This
+means that posts with modified content come to the top (which seems odd
+to me, but is presumably what the aggregator's author or operator
+wants),
+
+> Hah! That's so charitable I hope you can deduct it from your taxes. ;-)
+> --[[Joey]]
+
+but it also means that posts with insignificant edits (like
+adding tags) come to the top too. Atom defines `<updated>` to be the date
+of the last *significant* change, so it's fine that ikiwiki defaults to
+using the mtime, but it would be good to have a way for the author to
+say "that edit was insignificant, don't use that mtime".
+
+> Yes, this is a real limitiation of ikiwiki's atom support. --[[Joey]]
+
+See smcv's 'updated' branch for a basic implementation, which only affects
+the Atom `<updated>` field or the RSS equivalent.
+
+Other places the updated metadata item could be used (opinions on whether
+each should use it or not, please):
+
+* sorting by mtime in the inline directive
+* displaying "last edited" on ordinary pages
+
+> Tending toward no for both, but willing to be convinced otherwise..
+> [[merged|done]] --[[Joey]]
--- /dev/null
+Disabling some of action URLs is not possible now without creating own
+version of `templates/page.tmpl` file. For example, how to disable
+displaying `EDITURL`, `RECENTCHANGESURL` or `PREFSURL` without
+touching original `page.tmpl` template?
+
+Now I can only enable/disable `HISTORYURL` and `DISCUSSIONLINK`.
+It's not hard for me, but I think that the way to do it can be
+confusing for another Ikiwiki users. For example, if I don't
+want `HISTORYURL`, then I need to comment `historyurl` hash
+in setup file. But if I want to disable discussions, then I need
+to set `discussion=0` there. So, you can see that we don't have
+one common method here.
+
+Maybe Ikiwiki setup file should has more hashes for action URLs,
+for example `edit=[01]`, `recentchanges=[01]`, `prefs=[01]`
+and `history=[01]`?
+
+If you are curious why I need that features, I can clarify it.
+I'm building "parallel" version of my site. It means that I want
+to have one editable version for internal users and second only
+readable version (+ search feature) for external users. I build
+both versions on secure, internal machine from the same pages,
+of course, and separated setup files and different templates.
+The readable version of the site will be rsynced to clustered WWW
+front-ends immediately via `post-commit` hook file or periodically
+by Cron. I haven't decided how to do it yet. --[[Paweł|ptecza]]
+
+> You disable display of recentchanges by disabling that plugin.
+
+>> Thanks for the hint! I didn't think about it :)
+
+> You disable edit and preferences by not enabling a cgiurl at all.
+
+>> Yes, I've just discovered it. Unfortunately I need cgiurl,
+>> because I would like to use searching feature also for read-only
+>> pages.
+
+> Maybe page editing will become a plugin some day, or be made
+> configurable -- there are a few things like searching and websetup
+> (and possibly the poll plugin, aggregate webtrigger, and pingee)
+> that it may make sense to enable a cgi for even if you don't want to
+> allow page editing. --[[Joey]]
+
+>> I'm glad you agree that it may make sense :) --[[Paweł|ptecza]]
+
+>> We're in a similar situation with http://web.monkeysphere.info
+>> - wanting cgiurl so that our recentchanges page displays links,
+>> but not wanting to enable editing of pages (since we're also
+>> rsync'ing the html pages to mirrors) --[[Jamie]]
+
+editpage plugin implemented, [[done]] --[[Joey]]
+
+>> Joey, you're great! Thank you very, very, very much! :D --[[Paweł|ptecza]]
It would be nice to be able to delete pages online.
+
+> [[done]] though the [[plugins/remove]] plugin. --[[Will]]
Might be nice to support automatically generating an index based on headers
in a page, for long pages. This could be done as a sanitize hook that
-parsed the html, with a preprocessordirective that controlled it.
+parsed the html, with a directive that controlled it.
[[todo/done]]
+
+package IkiWiki::PageSpec;
+
-+sub match_relative($$;@) { #{{{
++sub match_relative($$;@) {
+ my $parent = shift;
+ my $spec = shift;
+ my %params = @_;
+ }
+ }
+ return IkiWiki::FailReason->new("$parent can't match $spec against anything");
-+} #}}}
++}
+
-+sub match_has_child($$;@) { #{{{
++sub match_has_child($$;@) {
+ my $page = shift;
+ my $childname = shift;
+ my $spec;
-+ if ($childname) { #{{{
++ if ($childname) {
+ $spec = "$page/$childname or $page/*/$childname";
-+ } #}}}
-+ else { #{{{
++ }
++ else {
+ $spec = "$page/*";
-+ } #}}}
++ }
+
+ return match_relative($page, $spec, @_);
-+} #}}}
++}
+
+1
</pre>
-[[tag patch]]
+[[!tag patch]]
-> This looks really interesting. It reminds me of XPath and its conditionals.
+> This looks really interesting. It reminds me of [[!wikipedia XPath]] and its conditionals.
> Those might actually work well adapted to pagespecs. For instance, to write
> "match any page with a child blah", you could just write *[blah] , or if you
> don't want to use relative-by-default in the conditionals, *[./blah].
> -- [[JoshTriplett]]
+
+> And it [[!taglink also_reminds_me|pagespec_in_DL_style]] of [[!wikipedia description logics]]: of course, given the relation `subpage` one could write a description-logic-style formula which would define the class of pages that are ("existentially") in a given relation (`subpage` or `inverse(subpage)*subpage`) to a certain other class of pages (e.g., named "blah") ("existentially" means there must exist a page, e.g., named "blah", which is in the given relation to the candidate).
+
+> Probably the model behind XPath is similar (although I don't know enough to say this definitely).--Ivan Z.
--- /dev/null
+[[!tag patch plugins/pagestats]]
+[[!template id=gitbranch branch=smcv/ready/among author="[[smcv]]"]]
+
+My `among` branch fixes [[todo/backlinks_result_is_lossy]], then uses that
+to provide pagestats for links from a subset of pages. From the docs included
+in the patch:
+
+> The optional `among` parameter limits counting to pages that match a
+> [[ikiwiki/PageSpec]]. For instance, to display a cloud of tags used on blog
+> entries, you could use:
+>
+> \[[!pagestats pages="tags/*" among="blog/posts/*"]]
+>
+> or to display a cloud of tags related to Linux, you could use:
+>
+> \[[!pagestats pages="tags/* and not tags/linux" among="tagged(linux)"]]
+
+I use this on my tag pages on one site, with the following template:
+
+ \[[!pagestats pages="tags/* and !tags/<TMPL_VAR raw_tag>
+ and !tags/photogallery"
+ among="tagged(<TMPL_VAR raw_tag>)"]]
+
+ \[[!inline pages="tagged(<TMPL_VAR raw_tag>)"
+ archive="yes" quick="yes" reverse="yes" timeformat="%x"]]
+
+--[[smcv]]
+
+> [[merged|done]] thanks --[[Joey]]
>>> Sure, a plugin is just a perl library so can easily be packaged
>>> separately.
-[[tag wishlist]]
+[[!tag wishlist]]
-[[tag wishlist]]
+[[!tag wishlist plugins/passwordauth]]
For sending out password reminder emails, the [[plugins/passwordauth]] plugin currently uses
the *[Mail::Sendmail](http://search.cpan.org/perldoc?Mail::Sendmail)* module.
--[[tschwinge]]
-> One that is in Debian is [[cpan Email::Send]], which can do SMTP and
+> One that is in Debian is [[!cpan Email::Send]], which can do SMTP and
> sendmail and some other methods and falls back through methods until one
> succeeds. I haven't tried to use it but it looks like a feasable
> candidate.
OK, so I'll have a look at replacing all email handling with *Email::Send*.
-[[tag patch]]
+[[!tag patch]]
*<http://www.thomas.schwinge.homeip.net/tmp/ikiwiki-sendmail.patch>*
Remaining TODOs:
* Resolve TODOs as denoted inside the patch.
- * Is it worthwhile to use and depend on [[cpan Return::Value]]
+ * Is it worthwhile to use and depend on [[!cpan Return::Value]]
just for this bit of functionality?
* Debian news file.
* ikiwiki news file.
> lost it. --[[Joey]]
Resent. --[[tschwinge]]
+
+> Debian now has Mail::Sender, Mail::SendEasy, and Email::Sender
+> (which, according to its dpkg description, "replaces the old and sometimes
+> problematic Email::Send library, which did a decent job at handling very
+> simple email sending tasks, but was not suitable for serious use, for a
+> variety of reasons"). Are any of those any better? It's unfortunate that
+> there doesn't seem to be a clear "best practice"... --[[smcv]]
--- /dev/null
+It was suggested that using ikiwiki as an alternative to pastebin services
+could be useful, especially if you want pastes to not expire and be
+cloneable.
+
+All you really need is a special purpose ikiwiki instance that you commit
+to by git. But a web interface for pasting could also be nice.
+
+There could be a directive that inserts a paste form onto a page. The form
+would have a big textarea for pasting into, and might also have a file
+upload button (for uploading instead of pasting). It could also copy the
+page edit form's dropdown of markup types, which would be especially useful
+if using the highlight plugin to support programming languages. The default
+should probably be txt, not mdwn, if the txt plugin is enabled.
+
+(There's a lot of overlap between that and editpage of course .. similar
+to the overlap between the comment form and editpage.)
+
+When posted, the form would just come up with a new, numeric subpage
+of the page it appears on, and save the paste there.
+
+Another thing that might be useful is a "copy" (or "paste as new") action
+on the action bar. This would take an existing paste and copy it into the
+paste edit form, for editing and saving under a new id.
+
+---
+
+A sample wiki configuration using this might be:
+
+* enable highlight and txt
+* enable anonok so anyone can paste; lock anonymous users down to only
+ creating new pastes, not editing other pages
+* disable modification of existing pastes (how? disabling editpage would
+ work, but that would disallow setting up anonymous git push)
+* enable comments, so that each paste can be commented on
+* enable getsource, so the source to a paste can easily be downloaded
+* optionally, enable untrusted git push
--- /dev/null
+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
+
+Merged, nice work. (Overkill having a test suite. ;-) --[[Joey]]
+
+> Thanks. If the testsuite reveals itself to be harder to maintain than
+> the plugin, my ego won't be offended to see it removed. It's been
+> nice to find a way, step by step, to work with you on this small
+> plugin thing. I'm starting to feel a bit at home in ikiwiki
+> sourcetree, which is great since I may have to start working on some
+> more ambitious ikiwiki stuff, such as the ~multilingual wiki
+> (master language + translations) support. Expect news from me on
+> this front in the next weeks. --[[intrigeri]]
+
+[[!tag patch done]]
--- /dev/null
+A "pingback" is a system whereby URLs you might reference in a blog post are
+contacted by the blog publishing software at publishing time (i.e., once) so
+that they might update a list of "pingbacks" to the URL. The originating
+URL's blog software might then display a list of pingbacks, or an excerpt of
+the text from your blog, perhaps interleaved with comments, etc.
+
+At a technical level, external URLs are extracted from your blog post by the
+blogging software, fetched, inspected for information to determine whether the
+remote server is configured to support pingbacks (look for link tags, or HTTP
+headers) and the relevant pingback URL sent an XML-RPC packet.
+
+There are other technologies to achieve the same thing: trackbacks predate
+pingbacks but are more vulnerable to spam due to design problems.
+
+The spec for pingbacks is at <http://www.hixie.ch/specs/pingback/pingback>.
+
+I would like to somehow use pingbacks in conjunction with ikiwiki. I suppose
+this could be achieved using a commit hook and some external software in which
+case I will consider this done with an entry in [[tips]]; otherwise a
+[[plugins|plugin]] to implement pingbacks would be great.
+
+-- [[Jon]] (Wed Jan 14 13:48:47 GMT 2009)
+
+> I think it's now possible to implement trackback and pingback receiving
+> support in ikiwiki. One easy way to do it would be to hook it into the
+> existing [[plugins/comments]] plugin -- each pingback/trackback that
+> ikiwiki recieves would result in the creation if a new comment, which
+> would be subject to the usual comment filtering (ie, blogspam) and
+> moderation and would then show up amoung the other, regular comments on
+> the page.
+>
+> (One wrinkle: would need to guard against duplicate pings. Maybe by
+> checking existing comments for any that have the same url?)
+>
+> As for sending trackbacks and pingbacks, this could fairly easily be
+> implemented using a `editcontent` hook. Since this hook is called
+> whenever a page is posted or edited, and gets the changed content, it can
+> simply scan it for urls (may have to htmlize first?), and send pings to
+> all urls found. --[[Joey]]
Suggestions of ideas for plugins:
+* enable editable, non-htmlized files
+
+ Some months ago, before upgrading my wiki, I used svn to check in an XML file
+ and a companion XSL file for client-side styling. That was cool, ikiwiki
+ copied them over unchanged and the file could be linked to as `\[[foo|foo.xml]]`.
+
+ I even had the XSL produce an `Edit` link at the top, because I wanted a simple
+ way for a web user to edit the XML. But I had to hack stuff to make the edit CGI
+ not say `foo.xml is not an editable page`.
+
+ I did that in a kind of slash-and-burn way, and apparently that's the one change
+ that was uncommitted when I upgraded ikiwiki, so now it's in the same place
+ as the wikiwyg project. On the bright side, that's a chance to think about how to
+ do it better.
+
+ Any suggestions for appropriate uses of existing plugins, or the plugin API,
+ to selectively add to the set of files in the working copy that the edit CGI
+ will consider editable? --ChapmanFlack 17July2008
+
+ > It looks like 80% of the job would be accomplished by hooking `htmlize` for
+ > the `.xml` extension. That would satisfy the `pagetype` test that causes
+ > the edit CGI to say `not an editable page`. (That happens too early for a
+ > `canedit` hook.) The `htmlize` hook could just
+ > copy in to out unchanged (this is an internal wiki, I'm not thinking hard
+ > about evil XML content right now). For extra credit, an `editcontent` hook
+ > could validate the XML. (Can an `editcontent` hook signal a content error?)
+
+ > The tricky bit seems to be to register the fact that the target file should
+ > have extension `.xml` and not `.html`. Maybe what's needed is a generalized
+ > notion of an `htmlize` hook, one that specifies its output extension as well
+ > as its input, and isn't assumed to produce html? --ChapmanFlack 17July2008
+
+ > Belay that, there's nothing good about trying to use `htmlize` for this; too
+ > many html-specific assumptions follow. For now I'm back to an embarrassing quick
+ > hack that allows editing my xml file. But here's the larger generalization I
+ > think this is driving at:
+
+ > IkiWiki is currently a tool that can compile a wiki by doing two things:
+ > 1. Process files of various input types _foo_ into a single output type, html, by
+ > finding suitable _foo_->html plugins, applying various useful transformations
+ > along the way.
+ > 1. Process files of other input types by copying them with no useful transformations at all.
+
+ > What it could be: a tool that compiles a wiki by doing this:
+ > 1. Process files of various input types _foo_ into various output types _bar_, by
+ > finding suitable _foo_->_bar_ plugins, applying various useful transformations along
+ > the way, but only those that apply to the _foo_->_bar_ conversion.
+ > 1. The second case above is now just a special case of 1 where _foo_->_foo_ for any
+ > unknown _foo_ is just a copy, and no other transformations apply.
+
+ > In some ways this seems like an easy and natural generalization. `%renderedfiles`
+ > is already mostly there, keeping the actual names of rendered files without assuming
+ > an html extension. There isn't a mechanism yet to say which transformations for
+ > linkification, preprocessing, etc., apply to which in/out types, but it could be
+ > easily added without a flag day. Right now, they _all_ apply to any input type for
+ > which an `htmlize` hook exists, and _none_ otherwise. That rule could be retained
+ > with an optional hook parameter available to override it.
+
+ > The hard part is just that right now the assumption of html as the one destination
+ > type is in the code a lot. --ChapmanFlack
+
+ >> Readers who bought this also liked: [[format_escape]], [[multiple_output_formats]]
+ >> --[[JeremieKoenig]]
+
* list of registered users - tricky because it sorta calls for a way to rebuild the page when a new user is registered. Might be better as a cgi?
> At best, this could only show the users who have logged in, not all
> permitted by the current auth plugin(s). HTTP auth would need
> web-server-specific code to list all users, and openid can't feasibly do so
> at all. --[[JoshTriplett]]
-* It would be nice to be able to have a button to show "Differences" (or
- "Show Diff") when editing a page. Is that an option that can be enabled?
- Using a plugin?
-
* For PlaceWiki I want to be able to do some custom plugins, including one
that links together subpages about the same place created by different
users. This seems to call for a plugin that applies to every page w/o any
Of course in these cases, you can add your request to a discussion page
and wait for someone with the access/confidence to apply them.
-Maybe this can be enhanced with a [[ikiwiki/PreprocessorDirective]]:
+Maybe this can be enhanced with a [[ikiwiki/Directive]]:
<pre>
-\[[suggest op=merge dstfile=trunk srcfile=branches/jk oldrev=1234 newrev=1342]]
+\[[!suggest op=merge dstfile=trunk srcfile=branches/jk oldrev=1234 newrev=1342]]
-\[[suggest op=move srcpage=/blog dstpage=/blog_support]]
+\[[!suggest op=move srcpage=/blog dstpage=/blog_support]]
-\[[suggest patch="""
+\[[!suggest patch="""
Index: IkiWiki/CGI.pm
===================================================================
--- IkiWiki/CGI.pm (révision 4119)
--- /dev/null
+A feature I originally requested on
+[[a_related_bug|bugs/openid_no_longer_pretty-prints_OpenIDs]]:
+
+ Allow the openid plugin to be loaded but disabled, for its side-effect of defining IkiWiki::openiduser
+
+ On various sites I have two IkiWiki instances running from the same
+ repository: one accessible via http and only accepting openid logins,
+ and one accessible via authenticated https and only accepting httpauth.
+ Ideally, the https version should still pretty-print OpenIDs seen in
+ git history.
+
+--[[smcv]]
+
+> I wonder if an option is the best approach. Maybe it would be better to
+> simply move `openiduser` into `userlink`, and thus always support openid
+> usernames whether the plugin is enabled or not. --[[Joey]]
+
+>> OK, implemented that as 'smcv/always-openid'; if you don't think that's
+>> bloating the IkiWiki core too much, please consider merging. The poll on
+>> [[news/openid]] indicates fairly strong support for *only* accepting OpenID
+>> logins, so I think recognising OpenIDs can reasonably be considered core
+>> functionality! --[[smcv]]
+
+>>> That seemed easier than expected, [[done]].
+>>> (I do wonder if the call to openiduser still needs to be evaled --
+>>> it was probably only evaled before in case it was not available, but
+>>> I have not carefully checked it to make sure it doesn't ever die. --[[Joey]]
+
+[[!tag patch]]
--- /dev/null
+I would like to add next plugin to Ikiwiki. It's `progressbar` or simply `progress`.
+I'm not sure what plugin name better is, probably that shorter ;) I know that
+[DokuWiki](http://wiki.splitbrain.org/plugin:progressbar) has similar plugin,
+so I think it can be useful also for Ikiwiki users.
+
+Here is proposition of the plugin syntax:
+
+ \[[!progress done=50]]
+
+Of course, `done` argument is integer from 0 to 100.
+
+A here is its HTML result:
+
+ <div class="progress">
+ <div class="progress-done" style="width: 50%">50%</div>
+ </div>
+
+Note: I was trying with `<span>` tags too, but that tag is inline, so I can't
+set `width` property for it.
+
+> In the poll plugin, I ended up using a `<hr>` for the progress-like
+> thing. One reason I did so is because it actually works in text-mode
+> browsers (w3m, lynx), that do not support css or colorized
+> divs. Since the hr is an element they display, just setting its width can
+> make a basic progress-type display. The style then makes it display
+> better in more capable browsers.
+>
+> The other advantage to that approach is that the htmlscrubber lets
+> through the `class` and `width` fields, that are all that are needed for
+> it to work. No need to work around htmlscrubber.
+>
+> So I suggest adapting this to use similar html. --[[Joey]]
+
+>> I just had a brief play with this. It seems there are some trade-offs involved.
+>> The `width` attribute of an `<hr>` tag is deprecated, but that's not the big one.
+>> I can't see how to place text next to an `<hr>` tag. I note that in the
+>> [[plugins/poll]] plugin there is text above and below the 'graph line', but none
+>> on the same line as the graph. I prefer the way the current code renders,
+>> with the percentage complete appearing as text inside the graph.
+>>
+>> So, if we use `hr` we get:
+>>
+>> - Graph line on text / non-css browsers
+>> - No percentage complete text on the same line as the graph line
+>> - Deprecated HTML
+>>
+>> If we use `div` we get:
+>>
+>> - Need to clean up after HTMLScrubber (which is not hard - already implemented)
+>> - Get the percentage written as text on text / non-css browsers
+>> - Get the percentage on the same line as the graph in css browsers
+>>
+>> I'm strongly in favour of having the percentage text label on the graph, and on
+>> text based browsers I think having the text label is enough -- the lack of the line
+>> in that case doesn't bother me.
+>> So, given the choice between the two suggested techniques, I'd take the second and
+>> stay with div... unless you know how to get text next to (or within) an `<hr>` tag. -- [[Will]]
+
+Default CSS styles for the plugin can be like below:
+
+ div.progress {
+ border: 1px solid #ddd;
+ /* border: 2px solid #ddd; */
+ width: 200px;
+ background: #fff;
+ padding: 2px;
+ /* padding: 0px; */
+ border: 2px solid #aaa;
+ background: #eee;
+ }
+ div.progress-done {
+ height: 14px;
+ background: #ff6600;
+ font-size: 12px;
+ text-align: center;
+ vertical-align: middle;
+ }
+
+You can use alternative, commented CSS code for `div.progress` if you dislike
+padding around done strip.
+
+Any comments? --[[Paweł|ptecza]]
+
+> Please make sure to always set a foreground color if a background color is
+> set, and use '!important' so the foreground color can be overridden. (CSS
+> best practices) --[[Joey]]
+
+>> Below is the CSS I've been using -- [[Will]]
+
+ div.progress {
+ margin-top: 1ex;
+ margin-bottom: 1ex;
+ border: 1px solid #888;
+ width: 400px;
+ background: #eee;
+ color: black !important;
+ padding: 1px;
+ }
+ div.progress-done {
+ background: #ea6 !important;
+ color: black !important;
+ text-align: center;
+ padding: 1px;
+ }
+
+> This looks like a nice idea. If I could add one further suggestion: Allow your
+> ratio to be a pair of pagespecs. Then you could have something like:
+
+ \[[!progress totalpages="bugs/* and backlink(milestoneB)" donepages="bugs/* and backlink(milestoneB) and !link(bugs/done)"]]
+
+> to have a progress bar marking how many bugs were compete for a
+> particular milestone. -- [[Will]]
+
+>> Thanks a lot for your comment, Will! It seems very interesting for me.
+>> I need to think more about improving that plugin. --[[Paweł|ptecza]]
+
+>> Attached is a [[patch]] (well, source) for this. You also need to add the proposed CSS above to `style.css`.
+>> At the moment this plugin interacts poorly with the [[plugins/htmlscrubber]] plugin.
+>> HTMLScrubber plugin removes the `style` attribute from the `progress-done` `div` tag, and so it defaults
+>> to a width of 100%. -- [[Will]]
+
+>>> Thank you for the code! I know how to fix that problem, because I had
+>>> the same issue while writing [[todo/color_plugin]] :) --[[Paweł|ptecza]]
+
+>>>> Ahh - good idea. Patch updated to work with HTMLScrubber. --[[Will]]
+
+>>>>> I like it, but I think that Joey should take a look at that patch too :)
+>>>>> --[[Paweł|ptecza]]
+
+>>>>>> Reviewed, looks excellent, added. [[done]] --[[Joey]]
+
+>>>>>>> Thanks a lot for you and Will! :) [[Paweł|ptecza]]
>> can use that as an alternative. I'm happy to chat about this, ping me..
>> --[sm](http://joyful.com)
-[[tag wishlist]]
+[[!tag wishlist]]
It would rock if I could view diffs from the web without going via feeds. I envision toggle-style buttons on the recentchanges page, or just links to the CGI, which then displays the diff... --[[madduck]]
-[[tag wishlist]]
+> The diffs are actually there, enabled by the `recentchangesdiff`
+> plugin, but they are hidden in the XHTML version by the stylesheet.
+> You might try a user stylesheet with `div.diff { display: block }`.
+> --[[JasonBlevins]]
+
+[[!tag wishlist]]
--- /dev/null
+This [[patch]] allows for `\[[sha1]]` substitution in the `diffurl`
+for git repositories. This is useful for use with [cgit][] which has
+diffurls of the following form:
+
+ /project.git/diff/\[[file]]?id=\[[sha1_commit]]
+
+ [cgit]: http://hjemli.net/git/cgit/
+
+ diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm
+ index 5bef928..164210d 100644
+ --- a/IkiWiki/Plugin/git.pm
+ +++ b/IkiWiki/Plugin/git.pm
+ @@ -518,6 +518,7 @@ sub rcs_recentchanges ($) {
+
+ my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : "";
+ $diffurl =~ s/\[\[file\]\]/$file/go;
+ + $diffurl =~ s/\[\[sha1\]\]/$sha1/go;
+ $diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go;
+ $diffurl =~ s/\[\[sha1_from\]\]/$detail->{'sha1_from'}/go;
+ $diffurl =~ s/\[\[sha1_to\]\]/$detail->{'sha1_to'}/go;
+
+> [[done]], but I called it `sha1_commit` since I think that's what it's
+> actually a sha1 of. --[[Joey]]
+
+>> I was at a loss for something more descriptive...I like that much
+>> better :) Thanks! --[[JasonBlevins]]
>
-[[tag patch]]
+[[!tag patch]]
> [[done]], although I left off the escapeHTML thing which seems to be in
> your patch by accident.
<http://www.reedmedia.net/~reed/tmp-sfhkcjkfrfh/rcs.pm>
-[[tag patch]]
+[[!tag patch]]
> Clearly needs some cleanup and perhaps some of the missing stubs
> implemented, before it can be included into ikiwiki.
--- /dev/null
+I've added three new functions to the ikiwiki VCS interface to support
+renaming and removing files using the web interface. The mercurial and
+tla [[rcs]] backends need implementions of these functions.
+
+(The maintainers of these backends have been mailed. --[[Joey]])
+
+Also, currently git is the only VCS to have support for
+[[untrusted_push|tips/untrusted_git_push]]. It _may_ be possible to
+implement it for other DVCS, if they offer a hook that can be used to check
+incoming pushes early.
Here's a full design for redoing recentchanges, based on Ethan's ideas:
* Add a recentchanges plugin that has a preprocessor directive:
- \[[recentchanges num=100 pages=* template=recentchanges.tmpl]]
+ \[[!recentchanges num=100 pages=* template=recentchanges.tmpl]]
If put on the [[recentchanges]] page, this would result in up to 100
recentchanges/change_$id.mdwn files being created.
* Which means the plugin has to store state and use a checkconfig hook
--- /dev/null
+In some wikis, (e.g. Mediawiki) after [[renaming|plugins/rename]]
+a page, the old page still exist but only redirect to the
+new page. This is convenient since external sites may
+have links pointing to the old url.
+
+If [[plugins/meta]] plugin is enabled, users can manually edit the
+page, and put in '\[[!meta redir=newpage]]', but this is
+not very convenient.
+
+
— NicolasLimare
-[[tag wishlist]]
+[[!tag wishlist]]
--- /dev/null
+While a relative pagespec like `./posts/*` will work, when used in a page
+such as `bdale/blog`, you cannot do
+`created_after(./posts/foo)` -- only `glob()` supports relative page
+references.
+
+The other pagespec functions should too, where appropriate.
+
+[[done]]
In version 2.16, several redir pages were put in for [[basewiki]] pages
that were moved. These redirs should be removed later. --[[Joey]]
+
+[[done]]
-[[tag wishlist]]
+[[!tag wishlist]]
HTML::Template is an okay templating kit, but it lacks a lot of powerful
features and thus makes it rather hard to give an ikiwiki site a consistent
-----
Yes, Template::Toolkit is very powerful. But I think it's somehow overkill for a wiki. HTML::Template can keep things simple, though. --[weakish](http://weakish.int.eu.org/blog/)
+
+I'd have to agree that Template::Toolkit is overkill and personally I'm not a fan, but it is very popular (there is even a book) and the new version (3) is alleged to be much more nimble than current version. --[[ajt]]
+
+HTML::Template's HTML-like markup prevents me from editing templates in KompoZer or other WYSIWYG HTML editors. The editor tries to render the template markup rather than display it verbatim, and large parts of the template become invisible. A markup syntax that doesn't confuse editors (such as Template::Toolkit's "[% FOO %]") may promote template customization. The ability to replace the template engine would be within the spirit of ikiwiki's extensibility. --Rocco
I imagine a plugin that modifies the login screen to use <http://recaptcha.net/>. You would then be required to fill in the captcha as well as log in in the normal way.
+-- [[users/Will]]
+
> I hate CAPTCHAs with a passion. Someone else is welcome to write such a
> plugin.
>
> This is still not fixed. I would have thought the following patch would
> have fixed this second issue, but it doesn't.
-(code snipped as a working patch is below)
+(code snipped as a working [[patch]] is below)
>> What seems to be happing here is that the openid plugin defines a
>> validate hook for openid_url that calls validate(). validate() in turn
--- a/IkiWiki/Plugin/openid.pm
+++ b/IkiWiki/Plugin/openid.pm
-@@ -18,6 +18,7 @@ sub getopt () { #{{{
+@@ -18,6 +18,7 @@ sub getopt () {
error($@) if $@;
Getopt::Long::Configure('pass_through');
GetOptions("openidsignup=s" => \$config{openidsignup});
+ GetOptions("openidneedscaptcha=s" => \$config{openidneedscaptcha});
- } #}}}
+ }
- sub formbuilder_setup (@) { #{{{
-@@ -61,6 +62,7 @@ sub formbuilder_setup (@) { #{{{
+ sub formbuilder_setup (@) {
+@@ -61,6 +62,7 @@ sub formbuilder_setup (@) {
# Skip all other required fields in this case.
foreach my $field ($form->field) {
next if $field eq "openid_url";
$form->field(name => $field, required => 0,
validate => '/.*/');
}
-@@ -96,6 +98,18 @@ sub validate ($$$;$) { #{{{
+@@ -96,6 +98,18 @@ sub validate ($$$;$) {
}
}
use strict;
use IkiWiki 2.00;
-sub import { #{{{
+sub import {
hook(type => "formbuilder_setup", id => "recaptcha", call => \&formbuilder_setup);
-} # }}}
+}
-sub getopt () { #{{{
+sub getopt () {
eval q{use Getopt::Long};
error($@) if $@;
Getopt::Long::Configure('pass_through');
GetOptions("reCaptchaPubKey=s" => \$config{reCaptchaPubKey});
GetOptions("reCaptchaPrivKey=s" => \$config{reCaptchaPrivKey});
-} #}}}
+}
-sub formbuilder_setup (@) { #{{{
+sub formbuilder_setup (@) {
my %params=@_;
my $form=$params{form};
});
}
}
-} # }}}
+}
# The following function is borrowed from
# Captcha::reCAPTCHA by Andy Armstrong and are under the PERL Artistic License
}
1;
-
>
> -- [[JoshTriplett]]
-[[tag wishlist]]
+[[!tag wishlist]]
--- /dev/null
+[[!tag wishlist blue-sky]]
+
+In the long term, I have been considering rewriting ikiwiki in haskell.
+It's appealing for a lot of reasons, including:
+
+* No need to depend on a C compiler and have wrappers. Instead, ikiwiki
+ binaries could be built on demand to do the things wrappers are used for
+ now (cgi, post-commit, etc).
+* Potentially much faster. One problem with the now very modular ikiwiki is
+ that it has to load up dozens of perl modules each time it runs, which
+ means both opening lots of files and evaluating them. A haskell version
+ could run from one pre-compiled file. Other speed efficienies are also
+ likely with haskell. For example, pandoc is apparently an order of
+ magnitude faster than perl markdown implementations.
+* Many plugins could be written in pure functional code, with no side
+ effects. Not all of them, of course.
+* It should be much easier to get ikiwiki to support parallel compilation
+ on multi-core systems using haskell.
+* A rewrite would be an opportunity to utterly break compatability and
+ redo things based on experience. Since the haskell libraries used for
+ markdown, templates, etc, are unlikely to be very compatable with the perl
+ versions, and since perl plugins obviously wouldn't work, and perl setup
+ files wouldn't be practical to keep, a lot of things would unavoidably
+ change, and at that point changinge everything else I can think of
+ probably wouldn't hurt (much).
+
+ - Re templates, it would be nice to have a template library that
+ doesn't use html-ish templating tags, since those are hard for users to
+ edit in html editors currently.
+ - This would be a chance to make WikiLinks with link texts read
+ "the right way round" (ie, vaguely wiki creole compatably).
+ - The data structures would probably be quite different.
+ - I might want to drop a lot of the command-line flags, either
+ requiring a setup file be used for those things, or leaving the
+ general-purpose `--set var=value` flag.
+ - Sometimes the current behavior of `--setup` seems confusing; it might
+ only cause a setup file to be read, and not force rebuild mode.
+ - Hard to say how the very high level plugin interface design would change,
+ but at the least some of the names of hooks could stand a rename, and
+ their parameter passing cleaned up.
+
+We know that a big, break-the-world rewrite like this can be a very
+bad thing for a project to attempt. It would be possible to support
+external plugins written in haskell today, without any rewrite; and a few
+of the benefits could be obtained by, eg, making the mdwn plugin be a
+haskell program that uses pandoc. I doubt that wouod be a good first step
+to converting ikiwiki to haskell, because such a program would have very
+different data structures and intercommuniucation than a pure haskell
+version.
+
+Some other things to be scared about:
+
+* By picking perl, I made a lot of people annoyed (and probably turned
+ several people away from using ikiwiki). But over time there turned out
+ to be a lot of folks who knew perl already (even if rustily), and made
+ some *very* useful contributions. I doubt there's as large a pool of haskell
+ programmers, and it's probably harder for a python user to learn haskell
+ than perl if they want to contribute to ikiwiki.
+* It might be harder for users of hosting services to install a haskell based
+ ikiwiki than the perl version. Such systems probably don't have ghc and
+ a bunch of haskell libraries. OTOH, it might be possible to build a
+ static binary at home and upload it, thus avoiding a messy installation
+ procedure entirely.
+* I can barely code in haskell yet. I'm probably about 100x faster at
+ programming in perl. I need to get some more practical experience before
+ I´m fast and seasoned enough in haskell to attempt such a project.
+ (And so far, progress at learning has been slow and I have not managed
+ to write anything serious in haskell.) --[[Joey]]
--- /dev/null
+Ok, I have to admit, I have no idea if this is an April fool's joke or not.
+Congratulations for demonstrating that April fools jokes can still be subtle
+(whether intentionally or not!) -- [[Jon]]
+
+> Having said all that, have you looked at erlang? Have you heard of couchdb?
+> I'd strongly recommend looking at that. -- [[Jon]]
+
+>> I've glanced at couchdb, but don't see how it would tie in with ikiwiki.
+>> --[[Joey]]
+
+
+>>> It doesn't really. I recently (re-)read about couchdb and thought that
+>>> what it was trying to do had some comparisons with the thinking going on
+>>> in [[todo/structured_page_data]]. -- [[Jon]]
> Now, the description field currently defaults to the wiki name,
> and that could indeed stand to be made configurable. Since the
> current (svn) version of ikiwiki supports long, word-wrapped
-> blocks of text as parameters to [[ikiwiki/PreProcessorDirective]]s, seems
+> blocks of text as parameters to [[ikiwiki/Directive]]s, seems
> to me the best way would be to simple modify inline.pm to make the
> descripion configurable by such parameter, with a fallback to the
> wiki name. You'll need to modify rsspage.tmpl to use whatever new
-The [[plugin/search]] plugin could use xapian terms to allow some special
+The [[plugins/search]] plugin could use xapian terms to allow some special
searches. For example, "title:foo", or "link:somepage", or "author:foo", or
"copyright:GPL".
--- /dev/null
+[[!tag wishlist]]
+
+Optional automatic section numbering would help reading: otherwise, a reader (like me) gets lost in the structure of a long page.
+
+I guess it is implementable with complex CSS... but one has first to compose this CSS in any case. So, this wish still has a todo status. --Ivan Z.
+
+And another aspect why this is related to ikiwiki, not just authoring a CSS, is that the style of the numbers (genereated by CSS probably) should match the style of the numbers in ikiwiki's [[plugins/toc]]. --Ivan Z.
-[[plugins/shortcut]] creates link shortcut [[ikiwiki/PreprocessorDirective]]s,
+[[plugins/shortcut]] creates link shortcut [[ikiwiki/Directive]]s,
which substitute their argument into the specified shortcut URL to generate
the link target, and use the argument as the link text. For example, given
-the example [[shortcuts]], `\[[wikipedia ikiwiki]]` generates a link to
+the example [[shortcuts]], `\[[!wikipedia ikiwiki]]` generates a link to
<http://en.wikipedia.org/wiki/ikiwiki>, with the link text "ikiwiki". This
works well in many cases; however, for things like the `debbug` example, it
simply uses the number as the link text, which does not always provide
enough context to understand the link at first glance. For example,
-`\[[debbug 397501]]` generates a link to <http://bugs.debian.org/397501>,
+`\[[!debbug 397501]]` generates a link to <http://bugs.debian.org/397501>,
with just "397501" as the link text. While [[plugins/template]] provides a
general solution for arbitrary cases, it would help to have a simple option
via the shortcut plugin to set the link text, with a `%s` substitution.
-Thus, something like `\[[shortcut name=debbug
+Thus, something like `\[[!shortcut name=debbug
url="http://bugs.debian.org/%s" desc="bug #%s"]]` might suffice on a
Debian-specific wiki to indicate a bug number, while a more general wiki
-might use something like `\[[shortcut name=debbug
+might use something like `\[[!shortcut name=debbug
url="http://bugs.debian.org/%s" desc="Debian bug #%s"]]`.
> [[todo/done]] --[[Joey]]
To create a "debfiles" [[shortcut|shortcuts]] that takes a package name, you
could just hardcode the architecture and distribution:
- \[[shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=unstable&arch=i386"]]
- \[[debfiles ikiwiki]]
+ \[[!shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=unstable&arch=i386"]]
+ \[[!debfiles ikiwiki]]
But what if you could have them as optional parameters instead? The syntax
for the invocation should look like this:
- \[[debfiles ikiwiki dist=testing]]
+ \[[!debfiles ikiwiki dist=testing]]
Some possible syntax choices for the shortcut definition:
- \[[shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=%(dist)s&arch=%(arch)s" dist="unstable" arch="i386"]]
- \[[shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=%(dist=unstable)s&arch=%(arch=i386)s"]]
- \[[shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=%{dist=unstable}&arch=%{arch=i386}"]]
- \[[shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=$*&searchmode=filelist&case=insensitive&version=${dist=unstable}&arch=${arch=i386}"]]
+ \[[!shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=%(dist)s&arch=%(arch)s" dist="unstable" arch="i386"]]
+ \[[!shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=%(dist=unstable)s&arch=%(arch=i386)s"]]
+ \[[!shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=%s&searchmode=filelist&case=insensitive&version=%{dist=unstable}&arch=%{arch=i386}"]]
+ \[[!shortcut name=debfiles url="http://packages.debian.org/cgi-bin/search_contents.pl?word=$*&searchmode=filelist&case=insensitive&version=${dist=unstable}&arch=${arch=i386}"]]
--[[JoshTriplett]]
Well, you can already do this kind of thing with templates. Invocation does
look different:
- \[[template id=debfiles package=ikiwiki dist=testing]]
+ \[[!template id=debfiles package=ikiwiki dist=testing]]
--[[Joey]]
> I think I would find templates sufficient, if:
>
> 1. I could use the name of the template as a preprocessor directive
-> (`\[[templatename ...]]`), rather than using the `template` directive
-> with an `id` argument (`\[[template id=templatename]]`).
+> (`\[[!templatename ...]]`), rather than using the `template` directive
+> with an `id` argument (`\[[!template id=templatename]]`).
> 2. Template invocation allowed bare values in addition to `key=value`
> arguments, and template definition supported some means to access the
-> value. This would allow `\[[debfiles ikiwiki]]` rather than
-> `\[[debfiles package=ikiwiki]]`.
+> value. This would allow `\[[!debfiles ikiwiki]]` rather than
+> `\[[!debfiles package=ikiwiki]]`.
> 3. I could use ikiwiki syntax in the template, not just HTML and
> HTML::Template. (If I can already do that, then [[/plugins/template]]
> should make that more clear.)
> If I don't understand this, can you give an HTML example? --[[JeremyReed]]
>> The problem is like that in [[bugs/shortcuts_don't_escape_from_Markdown]]. We would like to use
->> the shortcuts plugin but add a descriptive text -- in this case \[[xcbgit src/xcb.xsd|XML Schema...]]
+>> the shortcuts plugin but add a descriptive text -- in this case \[[!xcbgit src/xcb.xsd|XML Schema...]]
>> The file src/xcb.xsd could be any url, and the point of shortcuts is that you get to shorten it.
>> --Ethan
>>> However, I want to define a [[plugins/shortcut]] to save the typing. If I
>>> define something like `protogit` pointing to
>>> `http://gitweb.freedesktop.org/?p=xcb/proto.git;a=blob;hb=HEAD;f=%s`, then
->>> I can write `\[[protogit src/xcb.xsd]]`; however, I then can't change the
+>>> I can write `\[[!protogit src/xcb.xsd]]`; however, I then can't change the
>>> link text to anything other than what the shortcut defines as the link
>>> text. I want to write something like
>>> `\[[XML Schema for the X Window System Protocol|protogit src/xcb.xsd]]`,
---
-One possible alternative, would be a general `\[[url ]]` scheme for all kinds of links. As mentioned in [[Short_wikilinks]], I have wanted a way to enter links to the wiki with markdown-style references,
+One possible alternative, would be a general `\[[!url ]]` scheme for all kinds of links. As mentioned in [[Short_wikilinks]], I have wanted a way to enter links to the wiki with markdown-style references,
specifying the actual target elsewhere from the text, with just a short reference in the text. To facilitate automatic conversion from earlier (already markdownised) "blog", I finally ended up writing a custom plugin that simply gets the location of wikipage, and use markdown mechanisms:
Here [is][1] a link.
- [1]: [[l a_page_in_the_wiki]]
+ [1]: [[!l a_page_in_the_wiki]]
- Obviously [this]([[l another_page]]) also works, although the syntax is quite cumbersome.
+ Obviously [this]([[!l another_page]]) also works, although the syntax is quite cumbersome.
So that the 'l' plugin inserts the location the page there, and markdown does the rest. My plugin currently fails if it can't find the page, as that is sufficient for my needs. Differing colouring for non-existing pages is not doable in a straightforward manner with this approach.
-For external links, that is no concern, however. So you could define for each shortcut an alternative directive, that inserts the URL. Perhaps `\[[url shortcutname params]]` or `\[[@shortcutname params]]` (if the preprocessor supported the @), and this could be extended to local links in an obvious manner: `\[[url page]]` or `\[[@page]]`. Now, if you could just get rid off the parantheses for markdown, for the short inline links --[[tuomov]] (who'd really rather not have two separate linking mechanisms: ikiwiki's heavy syntax and markdown's lighter one).
+For external links, that is no concern, however. So you could define for each shortcut an alternative directive, that inserts the URL. Perhaps `\[[!url shortcutname params]]` or `\[[@shortcutname params]]` (if the preprocessor supported the @), and this could be extended to local links in an obvious manner: `\[[!url page]]` or `\[[@page]]`. Now, if you could just get rid off the parantheses for markdown, for the short inline links --[[tuomov]] (who'd really rather not have two separate linking mechanisms: ikiwiki's heavy syntax and markdown's lighter one).
---
-I've added code to make the \[[foo 123]] syntax accept a _desc_
+I've added code to make the \[[!foo 123]] syntax accept a _desc_
parameter. I've named it like this to signal that it overrides the
_desc_ provided at description time. `%s` is expanded here as well.
> `url` still seems reasonable, and simple. You could also use such shortcuts
> without markup at all, as an abbreviation mechanism:
>
-> \[[shortcut name=spi desc="Software in the Public Interest, Inc."]]].
-> \[[shortcut name=sosp desc="Symposium on Operating System Principles"]]].
-> \[[shortcut name=cacm desc="Communications of the ACM"]]].
+> \[[!shortcut name=spi desc="Software in the Public Interest, Inc."]]].
+> \[[!shortcut name=sosp desc="Symposium on Operating System Principles"]]].
+> \[[!shortcut name=cacm desc="Communications of the ACM"]]].
>
> --[[JoshTriplett]]
Other special things in my templates and site:
-* a sidebar with \[[include pages="notes/\*" template=foo]] while notes.mdwn has
- a \[[include pages="notes/*"]] and uses the sidebar; removed it, doesn't change
+* a sidebar with \[[!include pages="notes/\*" template=foo]] while notes.mdwn has
+ a \[[!include pages="notes/*"]] and uses the sidebar; removed it, doesn't change
* a template (biblio.tmpl) calling the "img" plugin with a template parameter as the
image filename; removed it, doesn't change
* some strange games with tags whose page calls a "map" directive to show other tags
>
> --[[Joey]]
-[[tag wishlist]]
+[[!template id=gitbranch branch=smcv/ready/optimize-depends author="[[smcv]]"]]
+
+>> I've been looking at optimizing ikiwiki for a site using
+>> [[plugins/contrib/album]] (which produces a lot of pages) and it seems
+>> that checking which pages depend on which pages does take a significant
+>> amount of time. The optimize-depends branch in my git repository
+>> avoids using `pagespec_merge()` for this (indeed it's no longer used
+>> at all), and instead represents dependencies as a list of pagespecs
+>> rather than a single pagespec. This does turn out to be faster, although
+>> not as much as I'd like. --[[smcv]]
+
+>>> [[Merged|done]] --[[smcv]]
+
+>>> I just wanted to note that there is a whole long discussion of dependencies and pagespecs on the [[todo/tracking_bugs_with_dependencies]] page. -- [[Will]]
+
+>>>> Yeah, I had a look at that (as the only other mention of `pagespec_merge`).
+>>>> I think I might have solved some of the problems mentioned there,
+>>>> actually - `pagespec_merge` no longer needs to exist in my branch (although
+>>>> I haven't actually deleted it), because the "or" operation is now done in
+>>>> the Perl code, rather than by merging pagespecs and translating. --[[smcv]]
+
+[[!template id=gitbranch branch=smcv/ready/remove-pagespec-merge author="[[smcv]]"]]
+
+>>>>> I've now added a patch to the end of that branch that deletes
+>>>>> `pagespec_merge` almost entirely (we do need to keep a copy around, in
+>>>>> ikiwiki-transition, but that copy doesn't have to be optimal or support
+>>>>> future features like [[tracking_bugs_with_dependencies]]). --[[smcv]]
+
+---
+
+Some questions on your optimize-depends branch. --[[Joey]]
+
+In saveindex it still or'd together the depends list, but the `{depends}`
+field seems only useful for backwards compatability (ie, ikiwiki-transition
+uses it still), and otherwise just bloats the index.
+
+> If it's acceptable to declare that downgrading IkiWiki requires a complete
+> rebuild, I'm happy with that. I'd prefer to keep the (simple form of the)
+> transition done automatically during a load/save cycle, rather than
+> requiring ikiwiki-transition to be run; we should probably say in NEWS
+> that the performance increase won't fully apply until the next
+> rebuild. --[[smcv]]
+
+>> It is acceptable not to support downgrades.
+>> I don't think we need a NEWS file update since any sort of refresh,
+>> not just a full rebuild, will cause the indexdb to be loaded and saved,
+>> enabling the optimisation. --[[Joey]]
+
+>>> A refresh will load the current dependencies from `{depends}` and save
+>>> them as-is as a one-element `{dependslist}`; only a rebuild will replace
+>>> the single complex pagespec with a long list of simpler pagespecs.
+>>> --[[smcv]]
+
+Is an array the right data structure? `add_depends` has to loop through the
+array to avoid dups, it would be better if a hash were used there. Since
+inline (and other plugins) explicitly add all linked pages, each as a
+separate item, the list can get rather long, and that single add_depends
+loop has suddenly become O(N^2) to the number of pages, which is something
+to avoid..
+
+> I was also thinking about this (I've been playing with some stuff based on the
+> `remove-pagespec-merge` branch). A hash, by itself, is not optimal because
+> the dependency list holds two things: page names and page specs. The hash would
+> work well for the page names, but you'll still need to iterate through the page specs.
+> I was thinking of keeping a list and a hash. You use the list for pagespecs
+> and the hash for individual page names. To make this work you need to adjust the
+> API so it knows which you're adding. -- [[Will]]
+
+> I wasn't thinking about a lookup hash, just a dedup hash, FWIW.
+> --[[Joey]]
+
+>> I was under the impression from previous code review that you preferred
+>> to represent unordered sets as lists, rather than hashes with dummy
+>> values. If I was wrong, great, I'll fix that and it'll probably go
+>> a bit faster. --[[smcv]]
+
+>>> It depends, really. And it'd certianly make sense to benchmark such a
+>>> change. --[[Joey]]
+
+>>>> Benchmarked, below. --[[smcv]]
+
+Also, since a lot of places are calling add_depends in a loop, it probably
+makes sense to just make it accept a list of dependencies to add. It'll be
+marginally faster, probably, and should allow for better optimisation
+when adding a lot of depends at once.
+
+> That'd be an API change; perhaps marginally faster, but I don't
+> see how it would allow better optimisation if we're de-duplicating
+> anyway? --[[smcv]]
+
+>> Well, I was thinking that it might be sufficient to build a `%seen`
+>> hash of dependencies inside `add_depends`, if the places that call
+>> it lots were changed to just call it once. Of course the only way to
+>> tell is benchmarking. --[[Joey]]
+
+>>> It doesn't seem that it significantly affects performance either way.
+>>> --[[smcv]]
+
+In Render.pm, we now have a triply nested loop, which is a bit
+scary for efficiency. It seems there should be a way to
+rework this code so it can use the optimised `pagespec_match_list`,
+and/or hoist some of the inner loop calculations (like the `pagename`)
+out.
+
+> I don't think the complexity is any greater than it was: I've just
+> moved one level of "loop" out of the generated Perl, to be
+> in visible code. I'll see whether some of it can be hoisted, though.
+> --[[smcv]]
+
+>> The call to `pagename` is the only part I can see that's clearly
+>> run more often than before. That function is pretty inexpensive, but..
+>> --[[Joey]]
+
+>>> I don't see anything that can be hoisted without significant refactoring,
+>>> actually. Beware that there are two pagename calls in the loop: one for
+>>> `$f` (which is the page we might want to rebuild), and one for `$file`
+>>> (which is the changed page that it might depend on). Note that I didn't
+>>> choose those names!
+>>>
+>>> The three loops are over source files, their lists of dependency pagespecs,
+>>> and files that might have changed. I see the following things we might be
+>>> doing redundantly:
+>>>
+>>> * If `$file` is considered as a potential dependency for more than
+>>> one `$f`, we evaluate `pagename($file)` more than once. Potential fix:
+>>> cache them (this turns out to save about half a second on the docwiki,
+>>> see below).
+>>> * If several pages depend on the same pagespec, we evaluate whether each
+>>> changed page matches that pagespec more than once: however, we do so
+>>> with a different location parameter every time, so repeated calls are,
+>>> in the general case, the only correct thing to do. Potential fix:
+>>> perhaps special-case "page x depends on page y and nothing else"
+>>> (i.e. globs that have no wildcards) into a separate hash? I haven't
+>>> done anything in this direction.
+>>> * Any preparatory work done by pagespec_match (converting the pagespec
+>>> into Perl, mostly?) is done in the inner loop; switching to
+>>> pagespec_match_list (significant refactoring) saves more than half a
+>>> second on the docwiki.
+>>>
+>>> --[[smcv]]
+
+Very good catch on img/meta using the wrong dependency; verified in the wild!
+(I've cherry-picked those bug fixes.)
+
+----
+
+Benchmarking results: I benchmarked by altering docwiki.setup to switch off
+verbose, running "make clean && ./Makefile.PL && make", and timing one rebuild
+of the docwiki followed by three refreshes. Before each refresh I used
+`touch plugins/*.mdwn` to have something significant to refresh.
+
+I'm assuming that "user" CPU time is the important thing here (system time was
+relatively small in all cases, up to 0.35 seconds per run).
+
+master at the time of rebasing: 14.20s to rebuild, 10.04/12.07/14.01s to
+refresh. I think you can see the bug clearly here - the pagespecs are getting
+more complicated every time!
+
+> I can totally see a bug here, and it's one I didn't think existed. Ie,
+> I thought that after the first refresh, the pagespec should stabalize,
+> and what it stabalized to was probably unnecessarily long, but not
+> growing w/o bounds!
+>
+> a) Explains why ikiwiki.info has been so slow lately. Well that and some
+> other things that overloaded the system.
+> b) Suggests to me we will probably want to force a rebuild on upgrade
+> when fixing this (via the mechanism in the postinst).
+>
+> I've investigated why the pagespecs keep growing: When page A changes,
+> its old depends are cleared. Then
+> page B that inlines A gets rebuilt, and its old depends are also cleared.
+> But page B also inlines page C; which means C gets re-rendered. And this
+> happens w/o its old depends being cleared, so C's depends are doubled.
+> --[[Joey]]
+
+After the initial optimization: 14.27s to rebuild, 8.26/8.33/8.26 to refresh.
+Success!
+
+Not pre-joining dependencies actually took about ~0.2s more; I don't know why.
+I'm worried that duplicates will just build up (again) in less simple cases,
+though, so 0.2s is probably a small price to pay for that not happening (it
+might well be experimental error, for that matter).
+
+> It's weird that the suggested optimisations to
+> `add_depends` had no effect. So, the commit message to
+> b6fcb1cb0ef27e5a63184440675d465fad652acf is actually wrong.. ? --[[Joey]]
+
+>> I'll try benchmarking again on the non-public wiki where I had the 4%
+>> speedup. The docwiki is so small that 4% is hard to measure... --[[smcv]]
+
+Not saving {depends} to the index, using a hash instead of a list to
+de-duplicate, and allowing add_depends to take an arrayref instead of a single
+pagespec had no noticable positive or negative effect on this test.
+
+> I see e4cd168ebedd95585290c97ff42234344bfed46c is still in your branch
+> though. I don't like using an arrayref, it could just take `($page, @depends)`.
+> and I don't see the need to keep it if it doesn't currently help.
+
+>> I'll drop it. --[[smcv]]
+
+> Is there any reason to keep 7227c2debfeef94b35f7d81f42900aa01820caa3
+> if it doesn't improve speed?
+> --[[Joey]]
+
+>> I'll try benchmarking on a more complex wiki and see whether it has a
+>> positive or negative effect. It does avoid being O(n**2) in number of
+>> dependencies. --[[smcv]]
+
+Memoizing the results of pagename brought the rebuild time down to 14.06s
+and the refresh time down to 7.96/7.92/7.92, a significant win.
+
+> Ok, that seems safe to memoize. (It's a real function and it isn't
+> called with a great many inputs.) Why did you chose to memoize it
+> explicitly rather than adding it to the memoize list at the top?
+
+>> It does depend on global variables, so using Memoize seemed like asking for
+>> trouble. I suppose what I did is equivalent to Memoize though... --[[smcv]]
+
+Refactoring to use pagespec_match_list looks more risky from a code churn
+point of view; rebuild now takes 14.35s, but refresh is only 7.30/7.29/7.28,
+another significant win.
+
+--[[smcv]]
+
+> I had mostly convinced myself that
+> `pagespec_match_list` would not lead to a speed gain here. My reasoning
+> was that you want to stop after finding one match, while `pagespec_match_list`
+> checks all pages for matches. So what we're seeing is that
+> on a rebuild, `@changed` is all pages, and not short-circuiting leads
+> to unnecessary work. OTOH, on refresh, `@changed` is small and I suppose
+> `pagespec_match_list`'s other slight efficiencies win out somehow.
+>
+> Welcome to the "I made ikiwiki twice as fast
+> and all I got was this lousy git sha1sum" club BTW :-) --[[Joey]]
+
+[[!tag wishlist patch patch/core]]
of very simple text parsing or regex application, to make it possible to write
shortcuts like these:
- [[mmlist listname@lists.example.org]] -> <listname@example.org> ([mailman page] (http://lists.example.org/mailman/listinfo/listname)
- [[debcl packagename]] -> [packagename changelog](http://packages.debian.org/changelogs/pool/main/p/packagename/current/changelog)
+ [[!mmlist listname@lists.example.org]] -> <listname@example.org> ([mailman page] (http://lists.example.org/mailman/listinfo/listname)
+ [[!debcl packagename]] -> [packagename changelog](http://packages.debian.org/changelogs/pool/main/p/packagename/current/changelog)
For shortcut definitions, a `match` parameter could supply a regex, and then the `url` and `desc` parameters could make use of the named or numbered groups from the match.
How about a skip option for [[plugins/inline]]? This would allow things like the following:
- \[[inline pages="news/*" show="5"]]
- \[[inline pages="news/*" skip="5" show="5" archive="yes"]]
+ \[[!inline pages="news/*" show="5"]]
+ \[[!inline pages="news/*" skip="5" show="5" archive="yes"]]
> I just wrote a patch. --Ethan
-Several [[ikiwiki/PreprocessorDirective]]s take ikiwiki-formatted text as arguments,
+Several [[ikiwiki/Directive]]s take ikiwiki-formatted text as arguments,
such as the `then` and `else` arguments of the new `if` directive, or the
`desc` argument of the `shortcut` directive. However, smileys do not work in
these arguments.
-Since the arguments to [[ikiwiki/PreprocessorDirective]]s might use the same syntax as
+Since the arguments to [[ikiwiki/Directive]]s might use the same syntax as
smileys for a different meaning, smiley substitution should not happen until
-after [[ikiwiki/PreprocessorDirective]]s.
+after [[ikiwiki/Directive]]s.
--[[JoshTriplett]]
--- /dev/null
+If I have a filesystem soft-link, e.g. "foo.mdwn" links to "bar.mdwn", it doesn't work.
+The page "foo/" does not exist.
+
+This is too bad, because sometimes it is convenient to have several different names for the same page.
+
+Could softlinks be handled gracefully by ikiwiki?
+
+> Soft links are explicitly not handled by IkiWiki as a [[security]] measure. If you want several names for
+> the same page, I suggest using the [[ikiwiki/directive/meta]] directive to make one page redirect to
+> another. -- [[Will]]
+
+>> Will is right. I don't plan to support symlinks. [[done]] --[[Joey]]
+
+>> With the appropriate template, inline can also help copy pages around [[DavidBremner]]
How about a direct link from the page header to the source of the latest version, to avoid the need to either use edit or navigate to the current version via the history link?
- I'd like this too (and might try to implement it). -- [[jondowland]]
+ I'd like this too (and might try to implement it). -- [[users/jon]]
+
+I just implemented this. There is one [[patch]] to the default page template, and a new plugin. -- [[Will]]
+
+All of this code is licensed under the GPLv2+. -- [[Will]]
+
+> The use of sessioncgi here seems undesirable: on wikis where anonymity is
+> not allowed, you'll be asked to log in. Couldn't you achieve the same thing
+> by loading the index with IkiWiki::loadindex, like [[plugins/goto]] does?
+> --[[smcv]]
+
+[[!template id=gitbranch branch=smcv/ready/getsource
+ author="[[Will]]/[[smcv]]"]]
+[[done]]
+
+>> I've applied the patch below in a git branch, fixed my earlier criticism,
+>> and also fixed a couple of other issues I noticed:
+>>
+>> * missing pages could be presented better as a real 404 page
+>> * the default Content-type should probably be UTF-8 since the rest of
+>> IkiWiki tends to assume that
+>> * emitting attachments (images, etc.) as text/plain isn't going to work :-)
+>>
+>> Any opinions on my branch? I think it's ready for merge, if Joey approves.
+>>
+>> --[[smcv]]
+
+>>> I need a copyright&license statement, so debian/copyright can be updated for
+>>> the plugin, before I can merge this. Otherwise ready. --[[Joey]]
+
+>>> That looks like a nice set of fixes. One more that might be worthwhile: instead of reading the page source into a var, and then writing it out later, it might be nice to just
+>>> `print readfile(srcfile(pagesources{$page}));` at the appropriate point. -- [[Will]]
+
+>>>> OK, I've committed that. --[[smcv]]
+
+----
+
+ diff --git a/templates/page.tmpl b/templates/page.tmpl
+ index f2f9c34..3176bed 100644
+ --- a/templates/page.tmpl
+ +++ b/templates/page.tmpl
+ @@ -46,6 +46,9 @@
+ <TMPL_IF NAME="HISTORYURL">
+ <li><a href="<TMPL_VAR HISTORYURL>">History</a></li>
+ </TMPL_IF>
+ +<TMPL_IF NAME="GETSOURCEURL">
+ +<li><a href="<TMPL_VAR GETSOURCEURL>">Get Source</a></li>
+ +</TMPL_IF>
+ <TMPL_IF NAME="PREFSURL">
+ <li><a href="<TMPL_VAR PREFSURL>">Preferences</a></li>
+ </TMPL_IF>
+
+----
+
+ #!/usr/bin/perl
+ package IkiWiki::Plugin::getsource;
+
+ use warnings;
+ use strict;
+ use IkiWiki;
+ use open qw{:utf8 :std};
+
+ sub import {
+ hook(type => "getsetup", id => "getsource", call => \&getsetup);
+ hook(type => "pagetemplate", id => "getsource", call => \&pagetemplate);
+ hook(type => "sessioncgi", id => "getsource", call => \&cgi_getsource);
+ }
+
+ sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1,
+ },
+ getsource_mimetype => {
+ type => "string",
+ example => "application/octet-stream",
+ description => "Mime type for returned source.",
+ safe => 1,
+ rebuild => 0,
+ },
+ }
+
+ sub pagetemplate (@) {
+ my %params=@_;
+
+ my $page=$params{page};
+ my $template=$params{template};
+
+ if (length $config{cgiurl}) {
+ $template->param(getsourceurl => IkiWiki::cgiurl(do => "getsource", page => $page));
+ $template->param(have_actions => 1);
+ }
+ }
+
+ sub cgi_getsource ($$) {
+ my $cgi=shift;
+ my $session=shift;
+
+ # Note: we use sessioncgi rather than just cgi
+ # because we need $IkiWiki::pagesources{} to be
+ # populated.
+
+ return unless (defined $cgi->param('do') &&
+ $cgi->param("do") eq "getsource");
+
+ IkiWiki::decode_cgi_utf8($cgi);
+
+ my $page=$cgi->param('page');
+
+ if ($IkiWiki::pagesources{$page}) {
+
+ my $data = IkiWiki::readfile(IkiWiki::srcfile($IkiWiki::pagesources{$page}));
+
+ if (! $config{getsource_mimetype}) {
+ $config{getsource_mimetype} = "text/plain";
+ }
+
+ print "Content-Type: $config{getsource_mimetype}\r\n";
+
+ print ("\r\n");
+
+ print $data;
+
+ exit 0;
+ }
+
+ error("Unable to find page source for page: $page");
+
+ exit 0;
+ }
+
+ 1
+
+[[done]] --[[smcv]]
--- /dev/null
+This is an idea from [[JoshTriplett]]. --[[Joey]]
+
+Some uses of ikiwiki, such as for a bug-tracking system (BTS), move a bit away from the wiki end
+of the spectrum, and toward storing structured data about a page or instead
+of a page.
+
+For example, in a bug report you might want to choose a severity from a
+list, enter a version number, and have a bug submitter or owner recorded,
+etc. When editing online, it would be nice if these were separate fields on
+the form, rather than the data being edited in the big edit form.
+
+There's a tension here between remaining a wiki with human-editable source
+files, containing freeform markup, and more structured data storage. I
+think that it would be best to include the structured data in the page,
+using a directive. Something like:
+
+ part of page content
+ \[[data yaml="<arbitrary yaml here>"]]
+ rest of page content
+
+As long as the position of the directive is not significant, it could be
+stripped out when web editing, the yaml used to generate/populate form fields,
+and then on save, the directive regenerated and inserted at top/bottom of
+the page.
+
+Josh thinks that yaml is probably a good choice, but the source could be a
+`.yaml` file that contains no directives, and just yaml. An addition
+complication in this scenario is, if the yaml included wiki page formatted content,
+ikiwiki would have to guess or be told what markup language it used.
+
+Either way, the yaml on the page would encode fields and their current content.
+Information about data types would be encoded elsewhere, probably on a
+parent page (using a separate directive). That way, all child pages could
+be forced to have the same fields.
+
+There would be some simple types like select, boolean, multiselect, string, wiki markup.
+Probably lists of these (ie, list of strings). Possibly more complex data
+structures.
+
+It should also be possible for plugins to define new types, and the type
+definitions should include validation of entered data, and how to prompt
+the user for the data.
+
+This seems conceptually straightforward, if possibly quite internally
+complex to handle the more complicated types and validation.
+
+One implementation wrinkle is how to build the html form. The editpage.tmpl
+currently overrides the standard [[!cpan CGI::FormBuilder]] generated form,
+which was done to make the edit page be laid out in a nice way. This,
+however, means that new fields cannot be easily added to it using
+[[!cpan CGI::FormBuilder]]. The attachment plugin uses the hack of bouilding
+up html by hand and dumping it into the form via a template variable.
+
+It would be nice if the type implementation code could just use
+FormBuilder, since its automatic form generation, and nice field validation
+model is a perfect match for structured data. But this problem with
+editpage.tmpl would have to be sorted out to allow that.
+
+Additional tie-ins:
+
+* Pagespecs that can select pages with a field with a given value, etc.
+ This should use a pagespec function like field(fieldname, value). The
+ semantics of this will depend on the type of the field; text fields will
+ match value against the text, and link fields will check for a link
+ matching the pagespec value.
+* The search plugin could allow searching for specific fields with specific
+ content. (xapian term search is a good fit).
+
+See also:
+
+[[tracking_bugs_with_dependencies]]
+
+> I was also thinking about this for bug tracking. I'm not sure what
+> sort of structured data is wanted in a page, so I decided to brainstorm
+> use cases:
+>
+> * You just want the page to be pretty.
+> * You want to access the data from another page. This would be almost like
+> like a database lookup, or the OpenOffice Calc [VLookup](http://wiki.services.openoffice.org/wiki/Documentation/How_Tos/Calc:_VLOOKUP_function) function.
+> * You want to make a pagespec depend upon the data. This could be used
+> for dependancy tracking - you could match against pages listed as dependencies,
+> rather than all pages linked from a given page.
+>
+>The first use case is handled by having a template in the page creation. You could
+
+
+
+
+>have some type of form to edit the data, but that's just sugar on top of the template.
+>If you were going to have a web form to edit the data, I can imagine a few ways to do it:
+>
+> * Have a special page type which gets compiled into the form. The page type would
+> need to define the form as well as hold the stored data.
+> * Have special directives that allow you to insert form elements into a normal page.
+>
+>I'm happy with template based page creation as a first pass...
+>
+>The second use case could be handled by a regular expression directive. eg:
+>
+> \[[regex spec="myBug" regex="Depends: ([^\s]+)"]]
+>
+> The directive would be replaced with the match from the regex on the 'myBug' page... or something.
+>
+>The third use case requires a pagespec function. One that matched a regex in the page might work.
+>Otherwise, another option would be to annotate links with a type, and then check the type of links in
+>a pagespec. e.g. you could have `depends` links and normal links.
+>
+>Anyway, I just wanted to list the thoughts. In none of these use cases is straight yaml or json the
+>obvious answer. -- [[Will]]
+
+>> Okie. I've had a play with this. A 'form' plugin is included inline below, but it is only a rough first pass to
+>> get a feel for the design space.
+>>
+>> The current design defines a new type of page - a 'form'. The type of page holds YAML data
+>> defining a FormBuilder form. For example, if we add a file to the wiki source `test.form`:
+
+ ---
+ fields:
+ age:
+ comment: This is a test
+ validate: INT
+ value: 15
+
+>> The YAML content is a series of nested hashes. The outer hash is currently checked for two keys:
+>> 'template', which specifies a parameter to pass to the FromBuilder as the template for the
+>> form, and 'fields', which specifies the data for the fields on the form.
+>> each 'field' is itself a hash. The keys and values are arguments to the formbuilder form method.
+>> The most important one is 'value', which specifies the value of that field.
+>>
+>> Using this, the plugin below can output a form when asked to generate HTML. The Formbuilder
+>> arguments are sanitized (need a thorough security audit here - I'm sure I've missed a bunch of
+>> holes). The form is generated with default values as supplied in the YAML data. It also has an
+>> 'Update Form' button at the bottom.
+>>
+>> The 'Update Form' button in the generated HTML submits changed values back to IkiWiki. The
+>> plugin captures these new values, updates the YAML and writes it out again. The form is
+>> validated when edited using this method. This method can only edit the values in the form.
+>> You cannot add new fields this way.
+>>
+>> It is still possible to edit the YAML directly using the 'edit' button. This allows adding new fields
+>> to the form, or adding other formbuilder data to change how the form is displayed.
+>>
+>> One final part of the plugin is a new pagespec function. `form_eq()` is a pagespec function that
+>> takes two arguments (separated by a ','). The first argument is a field name, the second argument
+>> a value for that field. The function matches forms (and not other page types) where the named
+>> field exists and holds the value given in the second argument. For example:
+
+ \[[!inline pages="form_eq(age,15)" archive="yes"]]
+
+>> will include a link to the page generated above.
+
+>>> Okie, I've just made another plugin to try and do things in a different way.
+>>> This approach adds a 'data' directive. There are two arguments, `key` and `value`.
+>>> The directive is replaced by the value. There is also a match function, which is similar
+>>> to the one above. It also takes two arguments, a key and a value. It returns true if the
+>>> page has that key/value pair in a data directive. e.g.:
+
+ \[[!data key="age" value="15"]]
+
+>>> then, in another page:
+
+ \[[!inline pages="data_eq(age,15)" archive="yes"]]
+
+>>> I expect that we could have more match functions for each type of structured data,
+>>> I just wanted to implement a rough prototype to get a feel for how it behaves. -- [[Will]]
+
+>> Anyway, here are the plugins. As noted above these are only preliminary, exploratory, attempts. -- [[Will]]
+
+>>>> I've just updated the second of the two patches below. The two patches are not mutually
+>>>> exclusive, but I'm leaning towards the second as more useful (for the things I'm doing). -- [[Will]]
+
+I think it's awesome that you're writing this code to explore the problem
+space, [[Will]] -- and these plugins are good stabs at at least part of it.
+Let me respond to a few of your comments.. --[[Joey]]
+
+On use cases, one use case is a user posting a bug report with structured
+data in it. A template is one way, but then the user has to deal with the
+format used to store the structured data. This is where a edit-time form
+becomes essential.
+
+> This was the idea with the 'form' plugin. With the 'data' plugin I was exploring
+> a different approach: try to keep the markup simple enough that the user can edit
+> the markup directly, and still have that be ok. I admit it is a stretch, but I thought
+> it worth exploring.
+
+Another use case is, after many such bugs have been filed,
+wanting to add a new field to each bug report. To avoid needing to edit
+every bug report it would be good if the fields in a bug report were
+defined somewhere else, so that just that one place can be edited to add
+the new field, and it will show up in each bug report (and in each bug
+report's edit page, as a new form field).
+
+> If I was going to do that, I'd use a perl script on a checked out
+> workspace. I think you're describing a rare operation and
+> so I'd be happy not having a web interface for it. Having said that,
+> if you just wanted to change the form for *new* pages, then you
+> can just edit the template used to create new pages.
+
+Re the form plugin, I'm uncomfortable with tying things into
+[[!cpan CGI::FormBuilder]] quite so tightly as you have.
+
+> Yeah :). But I wanted to explore the space and that was the
+> easiest way to start.
+
+CGI::FormBuilder
+could easily change in a way that broke whole wikis full of pages. Also,
+needing to sanitize FormBuilder fields with security implications is asking
+for trouble, since new FormBuilder features could add new fields, or
+add new features to existing fields (FormBuilder is very DWIM) that open
+new security holes.
+
+> There is a list of allowed fields. I only interpret those.
+
+I think that having a type system, that allows defining specific types,
+like "email address", by writing code (that in turn can use FormBuilder),
+is a better approach, since it should avoid becoming a security problem.
+
+> That would be possible. I think an extension to the 'data' plugin might
+> work here.
+
+One specific security hole, BTW, is that if you allow the `validate` field,
+FormBuilder will happily treat it as a regexp, and we don't want to expose
+arbitrary perl regexps, since they can at least DOS a system, and can
+probably be used to run arbitrary perl code.
+
+> I validate the validate field :). It only allows validate fields that match
+> `/^[\w\s]+$/`. This means you can really only use the pre-defined
+> validation types in FormBuilder.
+
+The data plugin only deals with a fairly small corner of the problem space,
+but I think does a nice job at what it does. And could probably be useful
+in a large number of other cases.
+
+> I think the data plugin is more likely to be useful than the form plugin.
+> I was thinking of extending the data directive by allowing an 'id' parameter.
+> When you have an id parameter, then you can display a small form for that
+> data element. The submission handler would look through the page source
+> for the data directive with the right id parameter and edit it. This would
+> make the data directive more like the current 'form' plugin.
+
+> That is making things significantly more complex for less significant gain though. --[[Will]]
+
+> Oh, one quick other note. The data plugin below was designed to handle multiple
+> data elements in a single directive. e.g.
+
+ \[[!data key="Depends on" link="bugs/bugA" link="bugs/bugB" value=6]]
+
+> would match `data_eq(Depends on,6)`, `data_link(Depends on,bugs/bugA)`, `data_link(Depends on,bugs/bugB)`
+> or, if you applied the patch in [[todo/tracking_bugs_with_dependencies]] then you can use 'defined pagespecs'
+> such as `data_link(Depends on,~openBugs)`. <a id="another_kind_of_links" />The ability to label links like this allows separation of
+> dependencies between bugs from arbitrary links.
+>> This issue (the need for distinguished kinds of links) has also been brought up in other discussions: [[tracking_bugs_with_dependencies#another_kind_of_links]] (deps vs. links) and [[tag_pagespec_function]] (tags vs. links). --Ivan Z.
+
+----
+
+ #!/usr/bin/perl
+ # Interpret YAML data to make a web form
+ package IkiWiki::Plugin::form;
+
+ use warnings;
+ use strict;
+ use CGI::FormBuilder;
+ use IkiWiki 2.00;
+
+ sub import {
+ hook(type => "getsetup", id => "form", call => \&getsetup);
+ hook(type => "htmlize", id => "form", call => \&htmlize);
+ hook(type => "sessioncgi", id => "form", call => \&cgi_submit);
+ }
+
+ sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+ }
+
+ sub makeFormFromYAML ($$$) {
+ my $page = shift;
+ my $YAMLString = shift;
+ my $q = shift;
+
+ eval q{use YAML};
+ error($@) if $@;
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+
+ my ($dataHashRef) = YAML::Load($YAMLString);
+
+ my @fields = keys %{ $dataHashRef->{fields} };
+
+ unshift(@fields, 'do');
+ unshift(@fields, 'page');
+ unshift(@fields, 'rcsinfo');
+
+ # print STDERR "Fields: @fields\n";
+
+ my $submittedPage;
+
+ $submittedPage = $q->param('page') if defined $q;
+
+ if (defined $q && defined $submittedPage && ! ($submittedPage eq $page)) {
+ error("Submitted page doensn't match current page: $page, $submittedPage");
+ }
+
+ error("Page not backed by file") unless defined $pagesources{$page};
+ my $file = $pagesources{$page};
+
+ my $template;
+
+ if (defined $dataHashRef->{template}) {
+ $template = $dataHashRef->{template};
+ } else {
+ $template = "form.tmpl";
+ }
+
+ my $form = CGI::FormBuilder->new(
+ fields => \@fields,
+ charset => "utf-8",
+ method => 'POST',
+ required => [qw{page}],
+ params => $q,
+ action => $config{cgiurl},
+ template => scalar IkiWiki::template_params($template),
+ wikiname => $config{wikiname},
+ header => 0,
+ javascript => 0,
+ keepextras => 0,
+ title => $page,
+ );
+
+ $form->field(name => 'do', value => 'Update Form', required => 1, force => 1, type => 'hidden');
+ $form->field(name => 'page', value => $page, required => 1, force => 1, type => 'hidden');
+ $form->field(name => 'rcsinfo', value => IkiWiki::rcs_prepedit($file), required => 1, force => 0, type => 'hidden');
+
+ my %validkey;
+ foreach my $x (qw{label type multiple value fieldset growable message other required validate cleanopts columns comment disabled linebreaks class}) {
+ $validkey{$x} = 1;
+ }
+
+ while ( my ($name, $data) = each(%{ $dataHashRef->{fields} }) ) {
+ next if $name eq 'page';
+ next if $name eq 'rcsinfo';
+
+ while ( my ($key, $value) = each(%{ $data }) ) {
+ next unless $validkey{$key};
+ next if $key eq 'validate' && !($value =~ /^[\w\s]+$/);
+
+ # print STDERR "Adding to field $name: $key => $value\n";
+ $form->field(name => $name, $key => $value);
+ }
+ }
+
+ # IkiWiki::decode_form_utf8($form);
+
+ return $form;
+ }
+
+ sub htmlize (@) {
+ my %params=@_;
+ my $content = $params{content};
+ my $page = $params{page};
+
+ my $form = makeFormFromYAML($page, $content, undef);
+
+ return $form->render(submit => 'Update Form');
+ }
+
+ sub cgi_submit ($$) {
+ my $q=shift;
+ my $session=shift;
+
+ my $do=$q->param('do');
+ return unless $do eq 'Update Form';
+ IkiWiki::decode_cgi_utf8($q);
+
+ eval q{use YAML};
+ error($@) if $@;
+ eval q{use CGI::FormBuilder};
+ error($@) if $@;
+
+ my $page = $q->param('page');
+
+ return unless exists $pagesources{$page};
+
+ return unless $pagesources{$page} =~ m/\.form$/ ;
+
+ return unless IkiWiki::check_canedit($page, $q, $session);
+
+ my $file = $pagesources{$page};
+ my $YAMLString = readfile(IkiWiki::srcfile($file));
+ my $form = makeFormFromYAML($page, $YAMLString, $q);
+
+ my ($dataHashRef) = YAML::Load($YAMLString);
+
+ if ($form->submitted eq 'Update Form' && $form->validate) {
+
+ #first update our data structure
+
+ while ( my ($name, $data) = each(%{ $dataHashRef->{fields} }) ) {
+ next if $name eq 'page';
+ next if $name eq 'rcs-data';
+
+ if (defined $q->param($name)) {
+ $data->{value} = $q->param($name);
+ }
+ }
+
+ # now write / commit the data
+
+ writefile($file, $config{srcdir}, YAML::Dump($dataHashRef));
+
+ my $message = "Web form submission";
+
+ IkiWiki::disable_commit_hook();
+ my $conflict=IkiWiki::rcs_commit($file, $message,
+ $form->field("rcsinfo"),
+ $session->param("name"), $ENV{REMOTE_ADDR});
+ IkiWiki::enable_commit_hook();
+ IkiWiki::rcs_update();
+
+ require IkiWiki::Render;
+ IkiWiki::refresh();
+
+ IkiWiki::redirect($q, "$config{url}/".htmlpage($page)."?updated");
+
+ } else {
+ error("Invalid data!");
+ }
+
+ exit;
+ }
+
+ package IkiWiki::PageSpec;
+
+ sub match_form_eq ($$;@) {
+ my $page=shift;
+ my $argSet=shift;
+ my @args=split(/,/, $argSet);
+ my $field=shift @args;
+ my $value=shift @args;
+
+ my $file = $IkiWiki::pagesources{$page};
+
+ if ($file !~ m/\.form$/) {
+ return IkiWiki::FailReason->new("page is not a form");
+ }
+
+ my $YAMLString = IkiWiki::readfile(IkiWiki::srcfile($file));
+
+ eval q{use YAML};
+ error($@) if $@;
+
+ my ($dataHashRef) = YAML::Load($YAMLString);
+
+ if (! defined $dataHashRef->{fields}->{$field}) {
+ return IkiWiki::FailReason->new("field '$field' not defined in page");
+ }
+
+ my $formVal = $dataHashRef->{fields}->{$field}->{value};
+
+ if ($formVal eq $value) {
+ return IkiWiki::SuccessReason->new("field value matches");
+ } else {
+ return IkiWiki::FailReason->new("field value does not match");
+ }
+ }
+
+ 1
+
+----
+
+ #!/usr/bin/perl
+ # Allow data embedded in a page to be checked for
+ package IkiWiki::Plugin::data;
+
+ use warnings;
+ use strict;
+ use IkiWiki 2.00;
+
+ my $inTable = 0;
+
+ sub import {
+ hook(type => "getsetup", id => "data", call => \&getsetup);
+ hook(type => "needsbuild", id => "data", call => \&needsbuild);
+ hook(type => "preprocess", id => "data", call => \&preprocess, scan => 1);
+ hook(type => "preprocess", id => "datatable", call => \&preprocess_table, scan => 1); # does this need scan?
+ }
+
+ sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => 1, # format plugin
+ },
+ }
+
+ sub needsbuild (@) {
+ my $needsbuild=shift;
+ foreach my $page (keys %pagestate) {
+ if (exists $pagestate{$page}{data}) {
+ if (exists $pagesources{$page} &&
+ grep { $_ eq $pagesources{$page} } @$needsbuild) {
+ # remove state, it will be re-added
+ # if the preprocessor directive is still
+ # there during the rebuild
+ delete $pagestate{$page}{data};
+ }
+ }
+ }
+ }
+
+ sub preprocess (@) {
+ my @argslist = @_;
+ my %params=@argslist;
+
+ my $html = '';
+ my $class = defined $params{class}
+ ? 'class="'.$params{class}.'"'
+ : '';
+
+ if ($inTable) {
+ $html = "<th $class >$params{key}:</th><td $class >";
+ } else {
+ $html = "<span $class >$params{key}:";
+ }
+
+ while (scalar(@argslist) > 1) {
+ my $type = shift @argslist;
+ my $data = shift @argslist;
+ if ($type eq 'link') {
+ # store links raw
+ $pagestate{$params{page}}{data}{$params{key}}{link}{$data} = 1;
+ my $link=IkiWiki::linkpage($data);
+ add_depends($params{page}, $link);
+ $html .= ' ' . htmllink($params{page}, $params{destpage}, $link);
+ } elsif ($type eq 'data') {
+ $data = IkiWiki::preprocess($params{page}, $params{destpage},
+ IkiWiki::filter($params{page}, $params{destpage}, $data));
+ $html .= ' ' . $data;
+ # store data after processing - allows pagecounts to be stored, etc.
+ $pagestate{$params{page}}{data}{$params{key}}{data}{$data} = 1;
+ }
+ }
+
+ if ($inTable) {
+ $html .= "</td>";
+ } else {
+ $html .= "</span>";
+ }
+
+ return $html;
+ }
+
+ sub preprocess_table (@) {
+ my %params=@_;
+
+ my @lines;
+ push @lines, defined $params{class}
+ ? "<table class=\"".$params{class}.'">'
+ : '<table>';
+
+ $inTable = 1;
+
+ foreach my $line (split(/\n/, $params{datalist})) {
+ push @lines, "<tr>" . IkiWiki::preprocess($params{page}, $params{destpage},
+ IkiWiki::filter($params{page}, $params{destpage}, $line)) . "</tr>";
+ }
+
+ $inTable = 0;
+
+ push @lines, '</table>';
+
+ return join("\n", @lines);
+ }
+
+ package IkiWiki::PageSpec;
+
+ sub match_data_eq ($$;@) {
+ my $page=shift;
+ my $argSet=shift;
+ my @args=split(/,/, $argSet);
+ my $key=shift @args;
+ my $value=shift @args;
+
+ if (! exists $IkiWiki::pagestate{$page}{data}) {
+ return IkiWiki::FailReason->new("page does not contain any data directives");
+ }
+
+ if (! exists $IkiWiki::pagestate{$page}{data}{$key}) {
+ return IkiWiki::FailReason->new("page does not contain data key '$key'");
+ }
+
+ if ($IkiWiki::pagestate{$page}{data}{$key}{data}{$value}) {
+ return IkiWiki::SuccessReason->new("value matches");
+ } else {
+ return IkiWiki::FailReason->new("value does not match");
+ }
+ }
+
+ sub match_data_link ($$;@) {
+ my $page=shift;
+ my $argSet=shift;
+ my @params=@_;
+ my @args=split(/,/, $argSet);
+ my $key=shift @args;
+ my $value=shift @args;
+
+ if (! exists $IkiWiki::pagestate{$page}{data}) {
+ return IkiWiki::FailReason->new("page $page does not contain any data directives and so cannot match a link");
+ }
+
+ if (! exists $IkiWiki::pagestate{$page}{data}{$key}) {
+ return IkiWiki::FailReason->new("page $page does not contain data key '$key'");
+ }
+
+ foreach my $link (keys %{ $IkiWiki::pagestate{$page}{data}{$key}{link} }) {
+ # print STDERR "Checking if $link matches glob $value\n";
+ if (match_glob($link, $value, @params)) {
+ return IkiWiki::SuccessReason->new("Data link on page $page with key $key matches glob $value: $link");
+ }
+ }
+
+ return IkiWiki::FailReason->new("No data link on page $page with key $key matches glob $value");
+ }
+
+ 1
--- /dev/null
+How about using JSON? YAML is popular in the Perl world, but the Web 2.0 world seems more excited about using JSON for data serialization. I find it easier to edit JSON by hand than YAML. -- [[Edward|/users/Edward_Betts]]
see in action in the preformatted patch below. So I don't see why the
default style sheet should do this. --[[Joey]]
-[[tag patch]]
+[[!tag patch]]
<pre>
diff --git a/basewiki/style.css b/basewiki/style.css
Syntax file for vim: http://www.peter-hoffmann.com/code/vim/ (Since a typical ikiwiki user usually use external editors. :))
-> Should be pretty easy to add a plugin to do it using [[cpan
+> Should be pretty easy to add a plugin to do it using [[!cpan
> Text::WikiCreole]]. --[[Joey]]
[[done]]
-I think it would be useful for ikiwiki to support [[debpkg sdf]] input,
+I think it would be useful for ikiwiki to support [[!debpkg sdf]] input,
which can be converted and rendered to many formats.
I should add, however, that SDF allows executing arbitrary perl code
from its documents; which means some sanitization would need to occur
before the document is fed to sdf.
--[[JeremieKoenig]]
-[[tag wishlist]]
+[[!tag wishlist]]
-ikiwiki should support writing plugins in other languages
+ikiwiki should support [[writing plugins in other languages|plugins/write/external]]
> [[done]] !!
>>> As a side note, the feature described above (having a form not to add a page but to expand it in a formated way) would be useful for other things when the content is short (timetracking, sub-todo list items, etc..) --[[hb]]
+# [[MarceloMagallon]]'s implementation
+
I've been looking into this. I'd like to implement a "blogcomments"
plugin. Looking at the code, I think the way to go is to have a
formbuilder_setup hook that uses a different template instead of the
What I ended up doing is write something like this to the page:
- [[blogcomment from="""Username""" timestamp="""12345""" subject="""Some text""" text="""the text of the comment"""]]
+ [[!blogcomment from="""Username""" timestamp="""12345""" subject="""Some text""" text="""the text of the comment"""]]
Each comment is processed to something like this:
-- [[MarceloMagallon]]
-# Code
+## Code
#!/usr/bin/perl
package IkiWiki::Plugin::comments;
use strict;
use IkiWiki '1.02';
- sub import { #{{{
+ sub import {
hook(type => "formbuilder_setup", id => "comments",
call => \&formbuilder_setup);
hook(type => "preprocess", id => "blogcomment",
call => \&preprocess);
- } # }}}
+ }
- sub formbuilder_setup (@) { #{{{
+ sub formbuilder_setup (@) {
my %params=@_;
my $cgi = $params{cgi};
my $form = $params{form};
$cgi->param('comments') : '';
my $comment=$cgi->param('blogcomment');
- $content.=qq{[[blogcomment from="""$name""" timestamp="""$timestamp""" subject="""$subject""" text="""$comment"""]]\n\n};
+ $content.=qq{[[!blogcomment from="""$name""" timestamp="""$timestamp""" subject="""$subject""" text="""$comment"""]]\n\n};
$content=~s/\n/\r\n/g;
$form->field(name => "editcontent", value => $content, force => 1);
- } # }}}
+ }
- sub preprocess (@) { #{{{
+ sub preprocess (@) {
my %params=@_;
my ($text, $date, $from, $subject, $r);
$r .= "</dl>\n" . $text . "</div>\n";
return $r;
- } # }}}
+ }
- 1;
\ No newline at end of file
+ 1;
+
+# [[smcv]]'s implementation
+
+I've started a smcvpostcomment plugin (to be renamed to postcomment if people like it, but I'm namespacing it while it's still experimental) which I think more closely resembles what Joey was after. The code is cargo-culted from a mixture of editpage and inline's "make a blog post" support - it has to use a lot of semi-internal IkiWiki:: functions (both of those plugins do too). It doesn't fully work yet, but I'll try to get it into a state where it basically works and can be published in the next week or two.
+
+My approach is:
+
+* Comments are intended to be immutable after posting (so, only editable by direct committers), so they go on internal pages (*._comment); these internal pages are checked in to the RCS (although later I might make this optional)
+
+* ?do=smcvpostcomment (in the CGI script) gives a form that lets logged-in users (later, optionally also anonymous users) create a new comment
+
+* \[[!smcvpostcomment]] just inserts a "Post comment" button into the current page, which goes to ?do=smcvpostcomment - it's intended to be used in conjunction with an \[[!inline]] that will display the comments
+
+* The title (subject line), author and authorurl are set with \[[!meta]] directives, just like the way aggregate does it (which means I'll probably have to disallow the use of those \[[!meta]] directives in the body of the comment, to avoid spoofing - obviously, spoofing can be detected by looking at RecentChanges or gitweb, but the expectation for blog-style comments is that the metadata seen in the comment can be trusted)
+
+* The initial plan is to have comments hard-coded to be in Markdown, with further directives not allowed - I'll relax this when I've worked out what ought to be allowed!
+
+I've also updated Marcelo's code (above) to current ikiwiki, and moved it to a "marceloblogcomment" namespace - it's in the "marcelocomments" branch of my repository (see <http://git.debian.org/?p=users/smcv/ikiwiki.git;a=log;h=refs/heads/marcelocomments>). I had to reconstitute the .tmpl file, which Marcelo didn't post here.
+
+--[[smcv]]
+
+OK, the postcomment branch in my repository contains an implementation. What
+do you think so far? Known issues include:
+
+* The combination of RSS/Atom links and the "post new comment..." button is
+ ugly - I need a way to integrate the "new comment" button into the feed links
+ somehow, like the way inline embeds its own "new blog post..." feature
+ (I don't think the current way really scales, though)
+
+* There are some tweakables (whether to commit comments into the VCS, whether
+ wikilinks are allowed, whether directives are allowed) that are theoretically
+ configurable, but are currently hard-coded
+
+* The wikilink/directive disarming doesn't work unless you have
+ prefixdirectives set (which I just realised)
+
+* \[[!smcvpostcomment]] now displays the comments too, by invoking \[[!inline]]
+ with suitable parameters - but it does so in a very ugly way
+
+* Start-tags in a comment with no corresponding end-tag break page formatting
+ (unless htmltidy is enabled - inline and aggregate have the same problem)
+
+* There is no access control, so anonymous users can always comment, and so
+ can all logged-in users. Perhaps we need to extend canedit() to support
+ different types of edit? Or perhaps I should ignore canedit() and make the
+ access control configurable via a parameter to \[[!smcvpostcomment]]?
+ I'd like to be able to let anonymous (or at least non-admin) users comment
+ on existing pages, but not edit or create pages (but perhaps I'm being too
+ un-wikiish).
+
+--[[smcv]]
+
+I've updated smcvpostcomment and publicised it as [[plugins/contrib/comments]]. --[[smcv]]
+
+> While there is still room for improvement and entirely other approaches,
+> I am calling this done since smcv's comments plugin is ready. --[[Joey]]
--- /dev/null
+There's been a lot of work on contrib syntax highlighting plugins. One should be
+picked and added to ikiwiki core.
+
+We want to support both converting whole source files into wiki
+pages, as well as doing syntax highlighting as a preprocessor directive
+(which is either passed the text, or reads it from a file). But,
+the [[ikiwiki/directive/format]] directive makes this easy enough to
+do if the plugin only supports whole source files. So, syntax plugins
+do no really need their own preprocessor directive, unless it makes
+things easier for the user.
+
+## The big list of possibilities
+
+* [[plugins/contrib/highlightcode]] uses [[!cpan Syntax::Highlight::Engine::Kate]],
+ operates on whole source files only, has a few bugs (see
+ [here](http://u32.net/Highlight_Code_Plugin/), and needs to be updated to
+ support [[bugs/multiple_pages_with_same_name]]. (Currently a 404 :-( )
+* [[!cpan IkiWiki-Plugin-syntax]] only operates as a directive.
+ Interestingly, it supports multiple highlighting backends, including Kate
+ and Vim.
+* [[plugins/contrib/syntax]] only operates as a directive
+ ([[not_on_source_code_files|automatic_use_of_syntax_plugin_on_source_code_files]]),
+ and uses [[!cpan Text::VimColor]].
+* [[plugins/contrib/sourcehighlight]] uses source-highlight, and operates on
+ whole source files only. Needs to be updated to
+ support [[bugs/multiple_pages_with_same_name]].
+* [[sourcecode|todo/automatic_use_of_syntax_plugin_on_source_code_files/discussion]]
+ also uses source-highlight, and operates on whole source files.
+ Updated to work with the fix for [[bugs/multiple_pages_with_same_name]]. Untested with files with no extension, e.g. `Makefile`.
+* [[users/jasonblevins]]'s code plugin uses source-highlight, and supports both
+ whole file and directive use.
+
+* [hlsimple](http://pivot.cs.unb.ca/git/?p=ikiplugins.git;a=blob_plain;f=IkiWiki/Plugin/hlsimple.pm;hb=HEAD) is a wrapper for the the perl module [[!cpan Syntax::Highlight::Engine::Simple]]. This is pure perl, pretty simple, uses css. It ought to be pretty fast (according to the author, and just because it is not external).
+On the other hand, there are not many predefined languages yet. Defining language syntaxes is about as much
+work as source-highlight, but in perl. I plan to package the base module for debian. Perhaps after the author
+releases the 5 or 6 language definitions he has running on his web site, it might be suitable for inclusion in ikiwiki. [[DavidBremner]]
+
+* [[plugins/highlight]] uses [highlight](http://www.andre-simon.de) via
+ its swig bindings. It optionally supports whole files, but also
+ integrates with the format directive to allow formatting of *any* of
+ highlight's supported formats. (For whole files, it uses either
+ keepextension or noextension, as appropriate for the type of file.)
+
+## General problems / requirements
+
+* Using non-perl syntax highlighting backends is slower. All things equal,
+ I'd prefer either using a perl module, or a multiple-backend solution that
+ can use a perl module as one option. (Or, if there's a great highlighter
+ python module, we could use an external plugin..)
+
+ Of course, some perl modules are also rather slow.. Kate, for example
+ can only process about 33 lines of C code, or 14 lines of
+ debian/changelog per second. That's **30 times slower than markdown**!
+
+ By comparison, source-highlight can do about 5000 lines of C code per
+ second... And launching the program 100 times on an empty file takes about
+ 5 seconds, which isn't bad. And, it has a C++ library, which it
+ seems likely perl bindings could be written for, to eliminate
+ even that overhead.
+ > [highlight](http://www.andre-simon.de) has similar features to source-highlight, and swig bindings
+ > that should make it trivial in principle to call from perl. I like highlight a bit better because
+ > it has a pass-through feature that I find very useful. My memory is unfortunately a bit fuzzy as to how
+ > well the swig bindings work. [[DavidBremner]]
+
+* Engines that already support a wide variety of file types are of
+ course preferred. If the engine doesn't support a particular type
+ of file, it could fall back to doing something simple like
+ adding line numbers. (IkiWiki-Plugin-syntax does this.)
+* XHTML output.
+* Emitting html that uses CSS to control the display is preferred,
+ since it allows for easy user customization. (Engine::Simple does
+ this; Kate can be configured to do it; source-highlight can be
+ made to do it via the switches `--css /dev/null --no-doc`)
+* Nothing seems to support
+ [[wiki-formatted_comments|wiki-formatted_comments_with_syntax_plugin]]
+ inside source files. Doing this probably means post-processing the
+ results of the highlighting engine, to find places where it's highlighted
+ comments, and then running them through the ikiwiki rendering pipeline.
+ This seems fairly doable with [[!cpan Syntax::Highlight::Engine::Kate]],
+ at least.
+* The whole-file plugins tend to have a problem that things that look like
+ wikilinks in the source code get munged into links by ikiwiki, which can
+ have confusing results. Similar problem with preprocessor directives.
+ One approach that's also been requested for eg,
+ [[plugins/contrib/mediawiki]] is to allow controlling which linkification
+ types a page type can have on it.
+
+ > The previous two points seem to be related. One thought: instead of
+ > getting the source from the `content` parameter, the plugin could
+ > re-load the page source. That would stop directives/links from
+ > being processed in the source. As noted above, comments
+ > could then be parsed for directives/links later.
+ >
+ > Would it be worth adding a `nodirectives` option when registering
+ > an htmlize hook that switches off directive and link processing before
+ > generating the html for a page?
+
+* The whole-file plugins all get confused if there is a `foo.c` and a `foo.h`.
+ This is trivially fixable now by passing the keepextension option when
+ registering the htmlize hooks, though. There's also a noextension option
+ that should handle the
+ case of source files with names that do not contain an extension (ie,
+ "Makefile") -- in this case you just register the while filename
+ in the htmlize hook.
+* Whole-file plugins register a bunch of htmlize hooks. The wacky thing
+ about it is that, when creating a new page, you can then pick "c" or
+ "h" or "pl" etc from the dropdown that normally has "Markdown" etc in it.
+ Is this a bug, or a feature? Even if a feature, plugins with many
+ extensions make the dropdown unusable..
+
+ Perhaps the thing to do here is to use the new `longname` parameter to
+ the format hook, to give them all names that will group together at or
+ near the end of the list. Ie: "Syntax: perl", "Source code: c", etc.
+
+---
+
+I'm calling this [[done]] since I added the [[plugins/highlight]]
+plugin. There are some unresolved issues touched on here,
+but they either have the own other bug reports, or are documented
+as semi-features in the docs to the plugin. --[[Joey]]
--- /dev/null
+sourcehighlight is annoyingly slow, but it does support wiki directives
+in comments. See [here](http://www.cs.unb.ca/~bremner/teaching/java_examples/snippet/ListMerge/)
+for an example (tags).
+
+> I think that is just a result of it expanding directives, and wikilinks,
+> everywhere in the file, which is generally a possible problem..
+> --[[Joey]]
+
+* * * * *
+
+I think having the option to choose source code page types from the
+dropdown list is definitely a feature. This gives users an easy way
+to contribute programs (say `.pl` files) or code snippets (like, for
+example, the Elisp area of the EmacsWiki). Actually, would there any
+other way to create a `.pl` file without write access to the
+repository? --[[JasonBlevins]]
+
+> Well, you can upload them as an attachment if the wiki is configured to
+> allow it. Having them in the drop down becomes a problem when there are
+> so many wacky extensions in there that you can't find anything.
+> --[[Joey]]
+
+>> I should just note that the
+>> [[sourcecode|todo/automatic_use_of_syntax_plugin_on_source_code_files/discussion]]
+>> plugin only adds the file extensions listed in the config. This shouldn't cause
+>> massive drop-down menu pollution. -- [[Will]]
+
+>>> That seems to be the way to go! --[[Joey]]
--- /dev/null
+Tables support a header row or no header, but do not support a header column.
+
+> I have proposed a patch to the table plugin that enable such behaviour: [[table/discussion|plugins/table/discussion]].
+>
+> -- [[AlexandreDupas]]
+
+>> [[applied|done]]
--- /dev/null
+Implementing tags in terms of links is clever, but it would be nice if it was
+opaque in both directions: tagging and matching tags. Writing pagespecs to
+find out which pages are tagged with a given name means that the pagespec is
+tied to whatever the tagbase is.
+
+This patch adds a pagespec function 'tag' which lets you write pagespecs to
+match tagged pages independent of whatever the tagbase is set to.
+
+ -- [[users/Jon]] 2009/02/17
+
+> So, this looks good, appreciate the patch.
+>
+> The only problem I see is it could be confusing if `tag(foo)` matched
+> a page that just linked to the tag via a wikilink, w/o actually tagging it.
+
+>> (My [[!taglink wishlist]].) Yes, this is confusing and not nice. I observed this misbehavior, because I wanted to match two different lists of pages (only tagged or linked in any way), but it didn't work. Would this feature require a complex patch? --Ivan Z.
+
+>>> If you link to a page 'foo' which happens to be a tag then the page you link from will turn up in the set of pages returned by tagged(foo). The only way to avoid this would be for the tag plugin to not use wikilinks as an implementation method. That itself would not be too hard to do, but there might be people relying on the older behaviour. A better alternative might be to have a "tag2" plugin (or a better name) which implements tagging entirely separately. -- [[Jon]]
+>>>> I see; at least, your response is encouraging (that it's not hard). I could even find some work that can give similar features: [[structured page data#another_kind_of_links]] -- they envisage a pagespec like `data_link(Depends on,bugs/bugA)`, thus a "separation of dependencies between bugs from arbitrary links".
+
+>>>> Indeed, having many relations that can be used in the formulas defining classes of objects (like pagespecs here) is a commonly imagined thing, so this would be a nice feature. (I'll be trying out the patches there first, probably.) In general, extending the language of pagespecs to something more powerful (like [[!wikipedia description logics]]) seems to be a nice possible feature. I saw more discussions of ideas [[!taglink about_the_extension_of_the_pagespec_language_in_the_direction_similar_to_description_logics|pagespec_in_DL_style]] somewhere else here. --Ivan Z.
+
+> One other thing, perhaps it should be called `tagged()`? --[[Joey]]
+
+[[!tag patch done]]
+
+ --- a/plugins/IkiWiki/Plugin/tag.pm 2009-02-16 11:30:11.000000000 +0000
+ +++ b/plugins/IkiWiki/Plugin/tag.pm 2009-02-17 15:40:03.000000000 +0000
+ @@ -125,4 +125,12 @@
+ }
+ }
+
+ +package IkiWiki::PageSpec;
+ +
+ +sub match_tag ($$;@) {
+ + my $page = shift;
+ + my $glob = shift;
+ + return match_link($page, IkiWiki::Plugin::tag::tagpage($glob));
+ +}
+ +
+ 1
Feature idea: I'd like to be able to tag pages in an ikiwiki blog with a
publication date, and have the option of building a blog that excludes
publication dates in the future. (meta pubdate= ?)
-
+
I'm using ikiwiki on git for a "tip of the day" RSS feed, and I'd like to
be able to queue up a bunch of items instead of literally putting in one
tip per day. In the future I think this will come in handy for other
> is a wiki compiler, if something causes content to change based on the
> date, then the wiki needs to be rebuilt periodically. So you'd need a
> cron job or something.
->
-> Implemeting this feature probably needs
-> [[todo/plugin_dependency_calulation]] to be implemented. --[[Joey]]
+>
+> Thinking about this some more, if you're going to have a cron job, you
+> could just set up a branch containing the future post. The branch could
+> have a name like 20080911. Then have the cron job git merge the day's
+> branch, if any, into master each day. And voila, post is completly hidden
+> until published. You'd want to avoid merge conflicts in your cron job ..
+> but they'd be unlikely if you limited yourself to just adding new
+> pages. Alternatively, for larger organisations wishing to deploy more
+> sweeping changes on a given date, replace cron job with intern.. ;-)
+> --[[Joey]]
+
+> > Good approach if you have one day on which a big change goes through, but
+> > often the reason for tagging with a publication date is so that you can
+> > dribble out articles one per day when you're gone for a week. Branches are easy
+> > in git, but it would still be an extra step to switch branches every time
+> > you edit a different day's article.
+> >
+> > And just to make it a little harder, some sites might want an internal
+> > copy of the wiki that _does_ build the future pages, just tags them with the publication
+> > date, for previewing.
+> >
+> > One more reason to have publication date: if you move a page from your old CMS to ikiwiki
+> > and want to have it show up in the right order in RSS feeds.
+> >
+> > I no longer have the original wiki for which I wanted this feature, but I can
+> > see using it on future ones. -- [[DonMarti]]
-Stuff still needing to be done with tags:
+Stuff still needing to be done with [[/tags]]:
* It's unfortunate that the rss category (tag) support doesn't include
a domain="" attribute in the category elements. That would let readers
--- /dev/null
+[[!tag wishlist]]
+
+Currently, [[plugins/brokenlinks]] supports filtering by the place where a broken wikilink is used.
+
+Filtering by the target of the broken link would also be useful, e.g.,
+
+ \[[!brokenlinks matching="tagbase/*"]]
+
+would list the tags not yet "filled out". --Ivan Z.
+ debug("ctime for '$file': ". localtime($ctime));
return $ctime;
- } #}}}
+ }
-[[tag patch done]]
+[[!tag patch done]]
* Need to get post commit hook code working.
* Need some example urls for web based diffs.
+* `rcs_commit_staged`, `rcs_rename`, `rcs_remove`, are not
+ implemented for tla, and so attachments, remove and rename plugins
+ cannot be used with it. (These should be fairly easy to add..)
-[[tag rcs/tla]]
+[[!tag rcs/tla]]
A simple plugin to allow per-page customization of a template by passing paramaters to HTML::Template. For those times when a whole pagetemplate is too much work. --Ethan
-[[tags patch]]
+[[!tag patch]]
+
+> The implementation looks fine to me (assuming it works with current ikiwiki),
+> apart from the "XXX" already noted in the patch. The design could reasonably
+> be considered premature generalization, though - how often do you actually
+> need to define new tmplvars?
+>
+> As for the page/destpage/preview thing, it would be good if the preprocess
+> hook could distinguish between software-supplied and user-supplied
+> parameters (the [[plugins/tag]] plugin could benefit from this too). Perhaps
+> the IkiWiki core could be modified so that
+> `hook(type => "preprocess", splitparams => 1, ...)` would invoke preprocess
+> with { page => "foo", destpage => "bar", ... } as a special first argument,
+> and the user-supplied parameters as subsequent arguments? Then plugins like
+> tag could use:
+>
+> my $ikiparams = shift;
+> my %params = @_;
+>
+> add_tags($ikiparams->{page}, keys %params);
+>
+> --[[smcv]]
+
+----
#!/usr/bin/perl
package IkiWiki::Plugin::tmplvars;
my %tmplvars;
- sub import { #{{{
+ sub import {
hook(type => "preprocess", id => "tmplvars", call => \&preprocess);
hook(type => "pagetemplate", id => "tmplvars", call => \&pagetemplate);
- } # }}}
+ }
- sub preprocess (@) { #{{{
+ sub preprocess (@) {
my %params=@_;
if ($params{page} eq $params{destpage}) {
}
}
- } # }}}
+ }
- sub pagetemplate (@) { #{{{
+ sub pagetemplate (@) {
my %params=@_;
my $template = $params{template};
}
return undef;
- } # }}}
+ }
1
--- /dev/null
+I find this plugin quite usefull. But one thing, I would like to be able to do is set a tmplvar e.g. in a sidebar so that it affects all Pages this sidebar is used in. --martin
--- /dev/null
+It would be nice if the [[plugins/toc]] plugin let you specify a header level "ceiling" above which (or above and including which) the headers would not be incorporated into the toc.
+
+Currently, the levels=X parameter lets you tweak how deep it will go for small headers, but I'd like to chop off the h1's (as I use them for my page title) -- [[Jon]]
It would be great if I could to this:
- \[[toc levels=3 skip=1]]
+ \[[!toc levels=3 skip=1]]
I use h1 for big title on each page, and don't want it in my toc on that page.
> another option is added, I wonder why you're using a h1 for a title on
> each page when the page name already appears at the top of each page. And
> if the page name isn't right for the title, you can use
-> \[[meta title="foo"]] to override it. And this purposefully doesn't show
+> \[[!meta title="foo"]] to override it. And this purposefully doesn't show
> up in the toc. --[[Joey]]
>> aaaahhh, I made a mistake. U used some other page.tmpl and title was hidden,
It would be nice if one could set the initial state of the toggleable area.
---[[[rdennis]]
+--[[rdennis]]
-[[tag plugins/toggle]]
+[[!tag plugins/toggle]]
[[done]]
--- /dev/null
+[[!tag patch patch/core]]
+
+I like the idea of [[tips/integrated_issue_tracking_with_ikiwiki]], and I do so on several wikis. However, as far as I can tell, ikiwiki has no functionality which can represent dependencies between bugs and allow pagespecs to select based on dependencies. For instance, I can't write a pagespec which selects all bugs with no dependencies on bugs not marked as done. --[[JoshTriplett]]
+
+> I started having a think about this. I'm going to start with the idea that expanding
+> the pagespec syntax is the way to attack this. It seems that any pagespec that is going
+> to represent "all bugs with no dependencies on bugs not marked as done" is going to
+> need some way to represent "bugs not marked as done" as a collection of pages, and
+> then represent "bugs which do not link to pages in the previous collection".
+>
+> One way to do this would be to introduce variables into the pagespec, along with
+> universal and/or existential [[!wikipedia Quantification]]. That looks quite complex.
+>
+>> I thought about this briefly, and got about that far.. glad you got
+>> further. :-) --[[Joey]]
+
+>> Or, one [[!taglink could_also_refer|pagespec_in_DL_style]] to the language of [[!wikipedia description logics]]: their formulas actually define classes of objects through quantified relations to other classes. --Ivan Z.
+>
+> Another option would be go with a more functional syntax. The concept here would
+> be to allow a pagespec to appear in a 'pagespec function' anywhere a page can. e.g.
+> I could pass a pagespec to `link()` and that would return true if there is a link to any
+> page matching the pagespec. This makes the variables and existential quantification
+> implicit. It would allow the example requested above:
+>
+>> `bugs/* and !*/Discussion and !link(bugs/* and !*/Discussion and !link(done))`
+>
+> Unfortunately, this is also going to make the pagespec parsing more complex because
+> we now need to parse nested sets of parentheses to know when the nested pagespec
+> ends, and that isn't a regular language (we can't use regular expression matching for
+> easy parsing).
+>
+>> Also, it may cause ambiguities with page names that contain parens
+>> (though some such ambigutities already exist with the pagespec syntax).
+>
+> One simplification of that would be to introduce some pagespec [[shortcuts]]. We could
+> then allow pagespec functions to take either pages, or named pagespec shortcuts. The
+> pagespec shortcuts would just be listed on a special page, like current [[shortcuts]].
+> (It would probably be a good idea to require that shortcuts on that page can only refer
+> to named pagespecs higher up that page than themselves. That would stop some
+> looping issues...) These shortcuts would be used as follows: when trying to match
+> a page (without globs) you look to see if the page exists. If it does then you have a
+> match. If it doesn't, then you look to see if a similarly named pagespec shortcut
+> exists. If it does, then you check that pagespec recursively to see if you have a match.
+> The ordering requirement on named pagespecs stops infinite recursion.
+>
+> Does that seem like a reasonable first approach?
+>
+> -- [[Will]]
+
+>> Having a separate page for the shortcuts feels unwieldly.. perhaps
+>> instead the shortcut could be defined earlier in the scope of the same
+>> pagespec that uses it?
+>>
+>> Example: `define(~bugs, bugs/* and !*/Discussion) and define(~openbugs, ~bugs and !link(done)) and ~openbugs and !link(~openbugs)`
+
+>>> That could work. parens are only ever nested 1 deep in that grammar so it is regular and the current parsing would be ok.
+
+>> Note that I made the "~" explicit, not implicit, so it could be left out. In the case of ambiguity between
+>> a definition and a page name, the definition would win.
+
+>>> That was my initial thought too :), but when implementing it I decided that requiring the ~ made things easier. I'll probably require the ~ for the first pass at least.
+
+>> So, equivilant example: `define(bugs, bugs/* and !*/Discussion) and define(openbugs, bugs and !link(done)) and openbugs and !link(openbugs)`
+>>
+
+>> Re recursion, it is avoided.. but building a pagespec that is O(N^X) where N is the
+>> number of pages in the wiki is not avoided. Probably need to add DOS prevention.
+>> --[[Joey]]
+
+>>> If you memoize the outcomes of the named pagespecs you can make in O(N.X), no?
+>>> -- [[Will]]
+
+>>>> Yeah, guess that'd work. :-)
+
+> <a id="another_kind_of_links" />One quick further thought. All the above discussion assumes that 'dependency' is the
+> same as 'links to', which is not really true. For example, you'd like to be able to say
+> "This bug does not depend upon [ [ link to other bug ] ]" and not have a dependency.
+> Without having different types of links, I don't see how this would be possible.
+>
+> -- [[Will]]
+
+>> I saw that this issue is targeted at by the work on [[structured page data#another_kind_of_links]]. --Ivan Z.
+
+Okie - I've had a quick attempt at this. Initial patch attached. This one doesn't quite work.
+And there is still a lot of debugging stuff in there.
+
+At the moment I've added a new preprocessor plugin, `definepagespec`, which is like
+shortcut for pagespecs. To reference a named pagespec, use `~` like this:
+
+ [ [!definepagespec name="bugs" spec="bugs/* and !*/Discussion"]]
+ [ [!definepagespec name="openbugs" spec="~bugs and !link(done)"]]
+ [ [!definepagespec name="readybugs" spec="~openbugs and !link(~openbugs)"]]
+
+At the moment the problem is in `match_link()` when we're trying to find a sub-page that
+matches the appropriate page spec. There is no good list of pages available to iterate over.
+
+ foreach my $nextpage (keys %IkiWiki::pagesources)
+
+does not give me a good list of pages. I found the same thing when I was working on
+this todo [[todo/Add_a_plugin_to_list_available_pre-processor_commands]].
+
+> I'm not sure why iterating over `%pagesources` wouldn't work here, it's the same method
+> used by anything that needs to match a pagespec against all pages..? --[[Joey]]
+
+>> My uchecked hypothesis is that %pagesources is created after the refresh hook.
+>> I've also been concerned about how globally defined pagespec shortcuts would interact with
+>> the page dependancy system. Your idea of internally defined shortcuts should fix that. -- [[Will]]
+
+>>> You're correct, the refresh hook is run very early, before pagesources
+>>> is populated. (It will be partially populated on a refresh, but will
+>>> not be updated to reflect new pages.) Agree that internally defined
+>>> seems the way to go. --[[Joey]]
+
+Immediately below is a patch which seems to basically work. Lots of debugging code is still there
+and it needs a cleanup, but I thought it worth posting at this point. (I was having problems
+with old style glob lists, so i just switched them off for the moment.)
+
+The following three inlines work for me with this patch:
+
+ Bugs:
+
+ [ [!inline pages="define(~bugs, bugs/* and ! */Discussion) and ~bugs" archive="yes"]]
+
+ OpenBugs:
+
+ [ [!inline pages="define(~bugs, bugs/* and ! */Discussion) and define(~openbugs,~bugs and !link(done)) and ~openbugs" archive="yes"]]
+
+ ReadyBugs:
+
+ [ [!inline pages="define(~bugs, bugs/* and ! */Discussion) and define(~openbugs,~bugs and !link(done)) and define(~readybugs,~openbugs and !link(~openbugs)) and ~readybugs" archive="yes"]]
+
+> Nice! Could the specfuncsref be passed in %params? I'd like to avoid
+> needing to change the prototype of every pagespec function, since several
+> plugins define them too. --[[Joey]]
+
+>> Maybe - it needs more thought. I also considered it when I was going though changing all those plugins :).
+>> My concern was that `%params` can contain other user-defined parameters,
+>> e.g. `link(target, otherparameter)`, and that means that the specFuncs could be clobbered by a user (or other
+>> weird security hole). I thought it better to separate it, but I didn't think about it too hard. I might move it to
+>> the first parameter rather than the second. Ikiwiki is my first real perl hacking and I'm still discovering
+>> good ways to write things in perl.
+>>
+>>>> `%params` contains the parameters passed to `pagespec_match`, not
+>>>> user-supplied parameters. The user-supplied parameter to a function
+>>>> like `match_glob()` or `match_link()` is passed in the second positional parameter. --[[Joey]]
+
+>>>>> OK. That seems reasonable then. The only problem is that my PERLfu is not strong enough to make it
+>>>>> work. I really have to wonder what substance was influencing the designers of PERL...
+>>>>> I can't figure out how to use the %params. And I'm pissed off enough with PERL that I'm not going
+>>>>> to try and figure it out any more. There are two patches below now. The first one uses an extra
+>>>>> argument and works. The second one tries to use %params and doesn't - take your pick :-). -- [[Will]]
+
+>> What do you think is best to do about `is_globlist()`? At the moment it requires that the 'second word', as
+>> delimited by a space and ignoring parens, is 'and' or 'or'. This doesn't hold in the above example pagespecs (so I just hard wired it to 0 to test my patch).
+>> My thought was just to search for 'and' or 'or' as words anywhere in the pagespec. Thoughts?
+
+>>> Dunno, we could just finish deprecating it. Or change the regexp to
+>>> skip over spaces in parens. (`/[^\s]+\s+([^)]+)/`) --[[Joey]]
+
+>>>> I think I have a working regexp now.
+
+>> Oh, one more thing. In pagespec_translate (now pagespec_makeperl), there is a part of the regular expression for `# any other text`.
+>> This contained `()`, which has no effect. I replaced that with `\(\)`, but that is a change in the definition of pagespecs unrelated to the
+>> rest of this patch. In a related change, commands were not able to contain `)` in their parameters. I've extended that so the cannot
+>> contain `(` or `)`. -- [[Will]]
+
+>>> `[^\s()]+` is a character class matching all characters not spaces or
+>>> parens. Since the pervious terminals in the regexp consume most
+>>> occurances of an open paren or close paren, it's unlikely for one to
+>>> get through to that part of the regexp. For example, "foo()" will be
+>>> matched by the command matcher; "(foo)" will be matched by the open
+>>> paren literal terminal. "foo(" and "foo)" can get through to the
+>>> end, and would be matched as a page name, if it didn't exclude parens.
+>>>
+>>> So why exclude them? Well, consider "foo and(bar and baz)". We don't
+>>> want it to match "and(" as a page name!
+>>>
+>>> Escaping the parens in the character class actually changes nothing; the
+>>> changed character class still matches all characters not spaces or
+>>> parens. (Try it!).
+>>>
+>>> Re commands containing '(', I don't really see any reason not to
+>>> allow that, unless it breaks something. --[[Joey]]
+
+>>>> Oh, I didn't realise you didn't need to escape parens inside []. All else I
+>>>> I understood. I have stopped commands from containing parens because
+>>>> once you allow that then you might have a extra level of depth in the parsing
+>>>> of define() statements. -- [[Will]]
+
+>>> Updated patch. Moved the specFuncsRef to the front of the arg list. Still haven't thought through the security implications of
+>>> having it in `%params`. I've also removed all the debugging `print` statements. And I've updated the `is_globlist()` function.
+>>> I think this is ready for people other than me to have a play. It is not well enough tested to commit just yet.
+>>> -- [[Will]]
+
+I've lost track of the indent level, so I'm going back to not indented - I think this is a working [[patch]] taking into
+account all comments above (which doesn't mean it is above reproach :) ). --[[Will]]
+
+> Very belated code review of last version of the patch:
+>
+> * `is_globlist` is no longer needed
+
+>> Good :)
+
+> * I don't understand why the pagespec match regexp is changed
+> from having flags `igx` to `ixgs`. Don't see why you
+> want `.` to match '\n` in it, and don't see any `.` in the regexp
+> anyway?
+
+>> Because you have to define all the named pagespecs in the pagespec, you sometimes end up with very long pagespecs. I found it useful to split them over multiple lines. That didn't work at one point and I added the 's' to make it work. I may have further altered the regex since then to make the 's' redundant. Remove it and see if multi-line pagespecs still work. :)
+
+>>> Well, I can tell you that multi-line pagespecs are supported w/o
+>>> your patch .. I use them all the time. The reason I find your
+>>> use of `/s` unlikely is because without it `\s` already matches
+>>> a newline. Only if you want to treat a newline as non-whitespace
+>>> is `/s` typically necessary. --[[Joey]]
+
+> * Some changes of `@_` to `%params` in `pagespec_makeperl` do not
+> make sense to me. I don't see where \%params is defined and populated,
+> except with `\$params{specFunc}`.
+
+>> I'm not a perl hacker. This was a mighty battle for me to get going.
+>> There is probably some battlefield carnage from my early struggles
+>> learning perl left here. Part of this is that @_ / @params already
+>> existed as a way of passing in extra parameters. I didn't want to
+>> pollute that top level namespace - just at my own parameter (a hash)
+>> which contained the data I needed.
+
+>>> I think I understand how the various `%params`
+>>> (there's not just one) work in your code now, but it's really a mess.
+>>> Explaining it in words would take pages.. It could be fixed by,
+>>> in `pagespec_makeperl` something like:
+>>>
+>>> my %specFuncs;
+>>> push @_, specFuncs => \%specFuncs;
+>>>
+>>> With that you have the hash locally available for populating
+>>> inside `pagespec_makeperl`, and when the `match_*` functions
+>>> are called the same hash data will be available inside their
+>>> `@_` or `%params`. No need to change how the functions are called
+>>> or do any of the other hacks.
+>>>
+>>> Currently, specFuncs is populated by building up code
+>>> that recursively calls `pagespec_makeperl`, and is then
+>>> evaluated when the pagespec gets evaluated. My suggested
+>>> change to `%params` will break that, but that had to change
+>>> anyway.
+>>>
+>>> It probably has a security hole, and is certianly inviting
+>>> one, since the pagespec definition is matched by a loose regexp (`.*`)
+>>> and then subject to string interpolation before being evaluated
+>>> inside perl code. I recently changed ikiwiki to never interpolate
+>>> user-supplied strings when translating pagespecs, and that
+>>> needs to happen here too. The obvious way, it seems to me,
+>>> is to not generate perl code, but just directly run perl code that
+>>> populates specFuncs.
+
+>>>> I don't think this is as bad as you make out, but your addition of the
+>>>> data array will break with the recursion my patch adds in pagespec_makeperl.
+>>>> To fix that I'll need to pass a reference to that array into pagespec_makeperl.
+>>>> I think I can then do the same thing to $params{specFuncs}. -- [[Will]]
+
+>>>>> You're right -- I did not think the recursive case through.
+>>>>> --[[Joey]]
+
+> * Seems that the only reason `match_glob` has to check for `~` is
+> because when a named spec appears in a pagespec, it is translated
+> to `match_glob("~foo")`. If, instead, `pagespec_makeperl` checked
+> for named specs, it could convert them into `check_named_spec("foo")`
+> and avoid that ugliness.
+
+>> Yeah - I wanted to make named specs syntactically different on my first pass. You are right in that this could be made a fallback - named specs always override pagenames.
+
+> * The changes to `match_link` seem either unecessary, or incomplete.
+> Shouldn't it check for named specs and call
+> `check_named_spec_existential`?
+
+>> An earlier version did. Then I realised it wasn't actually needed in that case - match_link() already included a loop that was like a type of existential matching. Each time through the loop it would
+>> call match_glob(). match_glob() in turn will handle the named spec. I tested this version briefly and it seemed to work. I remember looking at this again later and wondering if I had mis-understood
+>> some of the logic in match_link(), which might mean there are cases where you would need an explicit call to check_named_spec_existential() - I never checked it properly after having that thought.
+
+>>> In the common case, `match_link` does not call `match_glob`,
+>>> because the link target it is being asked to check for is a single
+>>> page name, not a glob.
+
+>>>> A named pagespec should fall into the glob case. These two pagespecs should be the same:
+
+ link(a*)
+
+>>>> and
+
+ define(aStar, a*) and link(~aStar)
+
+>>>> In the first case, we want the pagespec to match any page that links to a page matching the glob.
+>>>> In the second case, we want the pagespec to match any page that links to a page matching the named spec.
+>>>> match_link() was already doing existential part. The patches to this code were simply to remove the `lc()`
+>>>> call from the named pagespec name. Can that `lc` be removed entirely? -- [[Will]]
+
+>>>>> I think we could get rid of it. `bestlink` will lc it itself
+>>>>> if the uppercase version does not exist; `match_glob` matches
+>>>>> insensitively.
+>>>>> --[[Joey]]
+
+> * Generally, the need to modify `match_*` functions so that they
+> check for and handle named pagespecs seems suboptimal, if
+> only because there might be others people may want to use named
+> pagespecs with. It would be possible to move this check
+> to `pagespec_makeperl`, by having it check if the parameter
+> passed to a pagespec function looked like a named pagespec.
+> The only issue is that some pagespec functions take a parameter
+> that is not a page name at all, and it could be weird
+> if such a parameter were accidentially interpreted as a named
+> pagespec. (But, that seems unlikely to happen.)
+
+>> Possibly. I'm not sure which I prefer between the current solution and that one. Each have advantages and disadvantages.
+>> It really isn't much code for the match functions to add a call to check_named_spec_existential().
+
+>>> But if a plugin adds its own match function, it has
+>>> to explicitly call that code to support named pagespecs.
+
+>>>> Yes, and it can do that in just three lines of code. But if we automatically check for named pagespecs all the time we
+>>>> potentially break any matching function that doesn't accept pages, or wants to use multiple arguments.
+
+>>>>> 3 lines of code, plus the functions called become part of the API,
+>>>>> don't forget about that..
+>>>>>
+>>>>> Yes, I think that is the tradeoff, the question is whether to export
+>>>>> the additional complexity needed for that flexability.
+>>>>>
+>>>>> I'd be suprised if multiple argument pagespecs become necessary..
+>>>>> with the exception of this patch there has been no need for them yet.
+>>>>>
+>>>>> There are lots of pagespecs that take data other than pages,
+>>>>> indeed, that's really the common case. So far, none of them
+>>>>> seem likely to take data that starts with a `~`. Perhaps
+>>>>> the thing to do would be to check if `~foo` is a known,
+>>>>> named pagespec, and if not, just pass it through unchanged.
+>>>>> Then there's little room for ambiguity, and this also allows
+>>>>> pagespecs like `glob(~foo*)` to match the literal page `~foo`.
+>>>>> (It will make pagespec_merge even harder tho.. see below.)
+>>>>> --[[Joey]]
+
+>>>>>> I've already used multi-argument pagespec match functions in
+>>>>>> my data plugin. It is used for having different types of links. If
+>>>>>> you want to have multiple types of links, then the match function
+>>>>>> for them needs to take both the link name and the link type.
+>>>>>> I'm trying to think of a way we could have both - automatically
+>>>>>> handle the existential case unless the function indicates somehow
+>>>>>> that it'll do it itself. Any ideas? -- [[Will]]
+
+> * I need to check if your trick to avoid infinite recursion
+> works if there are two named specs that recursively
+> call one-another. I suspect it does, but will test this
+> myself..
+
+>> It worked for me. :)
+
+> * I also need to verify if memoizing the named pagespecs has
+> really guarded against very expensive pagespecs DOSing the wiki..
+
+> --[[Joey]]
+
+>> There is one issue that I've been thinking about that I haven't raised anywhere (or checked myself), and that is how this all interacts with page dependencies.
+>> Firstly, I'm not sure anymore that the `pagespec_merge` function will continue to work in all cases.
+
+>>> The problem I can see there is that if two pagespecs
+>>> get merged and both use `~foo` but define it differently,
+>>> then the second definition might be used at a point when
+>>> it shouldn't (but I haven't verified that really happens).
+>>> That could certianly be a show-stopper. --[[Joey]]
+
+>>>> I think this can happen in the new closure based code. I don't think this could happen in the old code. -- [[Will]]
+
+>>>> Even if that works, this is a good argument for having a syntactic difference between named pagespecs and normal pages.
+>>>> If you're joining two pagespecs with 'or', you don't want a named pagespec in the first part overriding a page name in the
+>>>> second part. Oh, and I assume 'or' has the right operator precedence that "a and b or c" is "(a and b) or c", and not "a and (b or c)" -- [[Will]]
+
+>>>>> Looks like its bracketed in the code anyway... -- [[Will]]
+
+>>>> Perhaps the thing to do is to have a `clear_defines()`
+>>>> function, then merging `A` and `B` yields `(A) or (clear_defines() and (B))`
+>>>> That would deal with both the cases where `A` and `B` differently
+>>>> define `~foo` as well as with the case where `A` defines `~foo` while
+>>>> `B` uses it to refer to a literal page.
+>>>> --[[Joey]]
+
+>>>>> I don't think this will work with the new patch, and I don't think it was needed with the old one.
+>>>>> Under the old patch, pagespec_makeperl() generated a string of unevaluated, self-contained, perl
+>>>>> code. When a new named pagespec was defined, a recursive call was made to get the perl code
+>>>>> for the pagespec, and then that code was used to add something like `$params{specFuncs}->{name} = sub {recursive code} and `
+>>>>> to the result of the calling function. This means that at pagespec testing time, when this code is executed, the
+>>>>> specFuncs hash is built up as the pagespec is checked. In the case of the 'or' used above, later redefinitions of
+>>>>> a named pagespec would have redefined the specFunc at the right time. It should have just worked. However...
+
+>>>>> Since my original patch, you started using closures for security reasons (and I can see the case for that). Unfortunately this
+>>>>> means that the generated perl code is no longer self-contained - it needs to be evaluated in the same closure it was generated
+>>>>> so that it has access to the data array. To make this work with the recursive call I had two options: a) make the data array a
+>>>>> reference that I pass around through the pagespec_makeperl() functions and have available when the code is finally evaluated
+>>>>> in pagespec_translate(), or b) make sure that each pagespec is evaluated in its correct closure and a perl function is returned, not a
+>>>>> string containing unevaluated perl code.
+
+>>>>> I went with option b). I did it in such a way that the hash of specfuncs is built up at translation time, not at execution time. This
+>>>>> means that with the new code you can call specfuncs that get defined out of order:
+
+ ~test and define(~test, blah)
+
+>>>>> but it also means that using a simple 'or' to join two pagespecs wont work. If you do something like this:
+
+ ~test and define(~test, foo) and define(~test, baz)
+
+>>>>> then the last definition (baz) takes precedence.
+>>>>> In the process of writing this I think I've come up with a way to change this back the way it was, still using closures. -- [[Will]]
+
+>>> My [[remove-pagespec-merge|should_optimise_pagespecs]] branch has now
+>>> solved all this by deleting the offending function :-) --[[smcv]]
+
+>> Secondly, it seems that there are two types of dependency, and ikiwiki
+>> currently only handles one of them. The first type is "Rebuild this
+>> page when any of these other pages changes" - ikiwiki handles this.
+>> The second type is "rebuild this page when set of pages referred to by
+>> this pagespec changes" - ikiwiki doesn't seem to handle this. I
+>> suspect that named pagespecs would make that second type of dependency
+>> more important. I'll try to come up with a good example. -- [[Will]]
+
+>>> Hrm, I was going to build an example of this with backlinks, but it
+>>> looks like that is handled as a special case at the moment (line 458 of
+>>> render.pm). I'll see if I can breapk
+>>> things another way. Fixing this properly would allow removal of that special case. -- [[Will]]
+
+>>>> I can't quite understand the distinction you're trying to draw
+>>>> between the two types of dependencies. Backlinks are a very special
+>>>> case though and I'll be suprised if they fit well into pagespecs.
+>>>> --[[Joey]]
+
+>>>>> The issue is that the existential pagespec matching allows you to build things that have similar
+>>>>> problems to backlinks.
+>>>>> e.g. the following inline:
+
+ \[[!inline pages="define(~done, link(done)) and link(~done)" archive=yes]]
+
+>>>>> includes any page that links to a page that links to done. Now imagine I add a new link to 'done' on
+>>>>> some random page somewhere - a page which some other page links to which didn't previously get included - the set of pages accepted by the pagespec, and hence the set of
+>>>>> pages inlined, will change. But, there is no dependency anywhere on the page that I altered, so
+>>>>> ikiwiki will not rebuild the page with the inline in it. What is happening is that the page that I altered affects
+>>>>> the set of pages matched by the pagespec without itself being matched by the pagespec, and hence included in the dependency list.
+
+>>>>> To make this work well, I think you need to recognise two types of dependencies for each page (and no
+>>>>> special cases for particular types of links, eg backlinks). The first type of dependency says, "The content of
+>>>>> this page depends upon the content of these other pages". The `add_depends()` in the shortcuts
+>>>>> plugin is of this form: any time the shortcuts page is edited, any page with a shortcut on it
+>>>>> is rebuilt. The inline plugin also needs to add dependencies of this form to detect when the inlined
+>>>>> content changes. By contrast, the map plugin does not need a dependency of this form, because it
+>>>>> doesn't actually care about the content of any pages, just which pages it needs to include (which we'll handle next).
+
+>>>>> The second type of dependency says, "The content of this page depends upon the exact set of pages matched
+>>>>> by this pagespec". The first type of dependency was about the content of some pages, the second type is about
+>>>>> which pages get matched by a pagespec. This is the type of dependency tracking that the map plugin needs.
+>>>>> If the set of pages matched by map pagespec changes, then the page with the map on it needs to be rebuilt to show a different list of pages.
+>>>>> Inline needs this type of dependency as well as the previous type - This type handles a change in which pages
+>>>>> are inlined, the previous type handles a change in the content of any of those pages. Shortcut does not need this type of
+>>>>> dependency. Most of the places that use `add_depends()` seem to need this type of dependency rather than the first type.
+
+>>>>>> Note that inline and map currently achieve the second type of dependency by
+>>>>>> explicitly calling `add_depends` for each page the displayed.
+>>>>>> If any of those pages are removed, the regular pagespec would not
+>>>>>> match them -- since they're gone. However, the explicit dependency
+>>>>>> on them does cause them to match. It's an ugly corner I'd like to
+>>>>>> get rid of. --[[Joey]]
+
+>>>>> Implementation Details: The first type of dependency can be handled very similarly to the current
+>>>>> dependency system. You just need to keep a list of pages that the content depends upon. You could
+>>>>> keep that list as a pagespec, but if you do this you might want to check that the pagespec doesn't change,
+>>>>> possibly by adding a dependency of the second type along with the dependency of the first type.
+
+>>>>>> An example of the current system not tracking enough data is
+>>>>>> where A inlines B which inlines C. A change to C will cause B to
+>>>>>> rebuild, but A will not "notice" that B has implicitly changed.
+>>>>>> That example suggests it might be fixable without explicitly storing
+>>>>>> data, by causing a rebuild of B to be treated as a change to B.
+>>>>>> --[[Joey]]
+
+>>>>> The second type of dependency is a little more tricky. For each page, we'd need a list of pagespecs that
+>>>>> the page depended on, and for each pagespec you'd want to store the list of pages that currently match it.
+>>>>> On refresh, you'd need to check each pagespec to see if the set of pages that match it has changed, and if
+>>>>> that set has changed, then rebuild the dependent page(s). Oh, and for this second type of dependency, I
+>>>>> don't think you can merge pagespecs. If I wanted to know if either "\*" or "link(done)" changes, then just checking
+>>>>> to see if the set of pages matched by "\* or link(done)" changes doesn't work.
+
+>>>>> The current system works because even though you usually want dependencies of the second type, the set of pages
+>>>>> referred to by a pagespec can only change if one of those pages itself changes. i.e. A dependency check of the
+>>>>> first type will catch a dependency change of the second type with current pagespecs.
+>>>>> This doesn't work with backlinks, and it doesn't work with existential matching. Backlinks are currently special-cased. I don't know
+>>>>> how to special-case existential matching - I suspect you're better off just getting the dependency tracking right.
+
+>>>>> I also tried to come up with other possible solutions: e.g. can we find the dependencies for a pagespec? That
+>>>>> would be the set of pages where a change on one of those pages could lead to a change in the set of pages matched by the pagespec.
+>>>>> For old-style pagespecs without backlinks, the dependency set for a pagespec is the same as the set of pages the pagespec matches.
+>>>>> Unfortunately, with existential matching, the set of pages that each
+>>>>> pagespec depends upon can quickly become "*", which is not very useful. -- [[Will]]
+
+Patch updated to use closures rather than inline generated code for named pagespecs. Also includes some new use of ErrorReason where appropriate. -- [[Will]]
+
+> * Perl really doesn't need forward declarations, honest!
+
+>> It complained (warning, not error) when I didn't use the forward declaration. :(
+
+> * I have doubts about memoizing the anonymous sub created by
+> `pagespec_translate`.
+
+>> This is there explicitly to make sure that runtime is polynomial and not exponential.
+
+> * Think where you wrote `+{}` you can just write `{}`
+
+>> Possibly :) -- [[Will]]
+
+----
+
+ diff --git a/IkiWiki.pm b/IkiWiki.pm
+ index 061a1c6..1e78a63 100644
+ --- a/IkiWiki.pm
+ +++ b/IkiWiki.pm
+ @@ -1774,8 +1774,12 @@ sub pagespec_merge ($$) {
+ return "($a) or ($b)";
+ }
+
+ -sub pagespec_translate ($) {
+ +# is perl really so dumb it requires a forward declaration for recursive calls?
+ +sub pagespec_translate ($$);
+ +
+ +sub pagespec_translate ($$) {
+ my $spec=shift;
+ + my $specFuncsRef=shift;
+
+ # Convert spec to perl code.
+ my $code="";
+ @@ -1789,7 +1793,9 @@ sub pagespec_translate ($) {
+ |
+ \) # )
+ |
+ - \w+\([^\)]*\) # command(params)
+ + define\(\s*~\w+\s*,((\([^()]*\)) | ([^()]+))+\) # define(~specName, spec) - spec can contain parens 1 deep
+ + |
+ + \w+\([^()]*\) # command(params) - params cannot contain parens
+ |
+ [^\s()]+ # any other text
+ )
+ @@ -1805,10 +1811,19 @@ sub pagespec_translate ($) {
+ elsif ($word eq "(" || $word eq ")" || $word eq "!") {
+ $code.=' '.$word;
+ }
+ - elsif ($word =~ /^(\w+)\((.*)\)$/) {
+ + elsif ($word =~ /^define\(\s*(~\w+)\s*,(.*)\)$/s) {
+ + my $name = $1;
+ + my $subSpec = $2;
+ + my $newSpecFunc = pagespec_translate($subSpec, $specFuncsRef);
+ + return if $@ || ! defined $newSpecFunc;
+ + $specFuncsRef->{$name} = $newSpecFunc;
+ + push @data, qq{Created named pagespec "$name"};
+ + $code.="IkiWiki::SuccessReason->new(\$data[$#data])";
+ + }
+ + elsif ($word =~ /^(\w+)\((.*)\)$/s) {
+ if (exists $IkiWiki::PageSpec::{"match_$1"}) {
+ push @data, $2;
+ - $code.="IkiWiki::PageSpec::match_$1(\$page, \$data[$#data], \@_)";
+ + $code.="IkiWiki::PageSpec::match_$1(\$page, \$data[$#data], \@_, specFuncs => \$specFuncsRef)";
+ }
+ else {
+ push @data, qq{unknown function in pagespec "$word"};
+ @@ -1817,7 +1832,7 @@ sub pagespec_translate ($) {
+ }
+ else {
+ push @data, $word;
+ - $code.=" IkiWiki::PageSpec::match_glob(\$page, \$data[$#data], \@_)";
+ + $code.=" IkiWiki::PageSpec::match_glob(\$page, \$data[$#data], \@_, specFuncs => \$specFuncsRef)";
+ }
+ }
+
+ @@ -1826,7 +1841,7 @@ sub pagespec_translate ($) {
+ }
+
+ no warnings;
+ - return eval 'sub { my $page=shift; '.$code.' }';
+ + return eval 'memoize (sub { my $page=shift; '.$code.' })';
+ }
+
+ sub pagespec_match ($$;@) {
+ @@ -1839,7 +1854,7 @@ sub pagespec_match ($$;@) {
+ unshift @params, 'location';
+ }
+
+ - my $sub=pagespec_translate($spec);
+ + my $sub=pagespec_translate($spec, +{});
+ return IkiWiki::ErrorReason->new("syntax error in pagespec \"$spec\"")
+ if $@ || ! defined $sub;
+ return $sub->($page, @params);
+ @@ -1850,7 +1865,7 @@ sub pagespec_match_list ($$;@) {
+ my $spec=shift;
+ my @params=@_;
+
+ - my $sub=pagespec_translate($spec);
+ + my $sub=pagespec_translate($spec, +{});
+ error "syntax error in pagespec \"$spec\""
+ if $@ || ! defined $sub;
+
+ @@ -1872,7 +1887,7 @@ sub pagespec_match_list ($$;@) {
+ sub pagespec_valid ($) {
+ my $spec=shift;
+
+ - my $sub=pagespec_translate($spec);
+ + my $sub=pagespec_translate($spec, +{});
+ return ! $@;
+ }
+
+ @@ -1919,6 +1934,68 @@ sub new {
+
+ package IkiWiki::PageSpec;
+
+ +sub check_named_spec($$;@) {
+ + my $page=shift;
+ + my $specName=shift;
+ + my %params=@_;
+ +
+ + return IkiWiki::ErrorReason->new("Unable to find specFuncs in params to check_named_spec()!")
+ + unless exists $params{specFuncs};
+ +
+ + my $specFuncsRef=$params{specFuncs};
+ +
+ + return IkiWiki::ErrorReason->new("Named page spec '$specName' is not valid")
+ + unless (substr($specName, 0, 1) eq '~');
+ +
+ + if (exists $specFuncsRef->{$specName}) {
+ + # remove the named spec from the spec refs
+ + # when we recurse to avoid infinite recursion
+ + my $sub = $specFuncsRef->{$specName};
+ + delete $specFuncsRef->{$specName};
+ + my $result = $sub->($page, %params);
+ + $specFuncsRef->{$specName} = $sub;
+ + return $result;
+ + } else {
+ + return IkiWiki::ErrorReason->new("Page spec '$specName' does not exist");
+ + }
+ +}
+ +
+ +sub check_named_spec_existential($$$;@) {
+ + my $page=shift;
+ + my $specName=shift;
+ + my $funcref=shift;
+ + my %params=@_;
+ +
+ + return IkiWiki::ErrorReason->new("Unable to find specFuncs in params to check_named_spec_existential()!")
+ + unless exists $params{specFuncs};
+ + my $specFuncsRef=$params{specFuncs};
+ +
+ + return IkiWiki::ErrorReason->new("Named page spec '$specName' is not valid")
+ + unless (substr($specName, 0, 1) eq '~');
+ +
+ + if (exists $specFuncsRef->{$specName}) {
+ + # remove the named spec from the spec refs
+ + # when we recurse to avoid infinite recursion
+ + my $sub = $specFuncsRef->{$specName};
+ + delete $specFuncsRef->{$specName};
+ +
+ + foreach my $nextpage (keys %IkiWiki::pagesources) {
+ + if ($sub->($nextpage, %params)) {
+ + my $tempResult = $funcref->($page, $nextpage, %params);
+ + if ($tempResult) {
+ + $specFuncsRef->{$specName} = $sub;
+ + return IkiWiki::SuccessReason->new("Existential check of '$specName' matches because $tempResult");
+ + }
+ + }
+ + }
+ +
+ + $specFuncsRef->{$specName} = $sub;
+ + return IkiWiki::FailReason->new("No page in spec '$specName' was successfully matched");
+ + } else {
+ + return IkiWiki::ErrorReason->new("Named page spec '$specName' does not exist");
+ + }
+ +}
+ +
+ sub derel ($$) {
+ my $path=shift;
+ my $from=shift;
+ @@ -1937,6 +2014,10 @@ sub match_glob ($$;@) {
+ my $glob=shift;
+ my %params=@_;
+
+ + if (substr($glob, 0, 1) eq '~') {
+ + return check_named_spec($page, $glob, %params);
+ + }
+ +
+ $glob=derel($glob, $params{location});
+
+ my $regexp=IkiWiki::glob2re($glob);
+ @@ -1959,8 +2040,9 @@ sub match_internal ($$;@) {
+
+ sub match_link ($$;@) {
+ my $page=shift;
+ - my $link=lc(shift);
+ + my $fullLink=shift;
+ my %params=@_;
+ + my $link=lc($fullLink);
+
+ $link=derel($link, $params{location});
+ my $from=exists $params{location} ? $params{location} : '';
+ @@ -1975,25 +2057,37 @@ sub match_link ($$;@) {
+ }
+ else {
+ return IkiWiki::SuccessReason->new("$page links to page $p matching $link")
+ - if match_glob($p, $link, %params);
+ + if match_glob($p, $fullLink, %params);
+ $p=~s/^\///;
+ $link=~s/^\///;
+ return IkiWiki::SuccessReason->new("$page links to page $p matching $link")
+ - if match_glob($p, $link, %params);
+ + if match_glob($p, $fullLink, %params);
+ }
+ }
+ return IkiWiki::FailReason->new("$page does not link to $link");
+ }
+
+ sub match_backlink ($$;@) {
+ - return match_link($_[1], $_[0], @_);
+ + my $page=shift;
+ + my $backlink=shift;
+ + my @params=@_;
+ +
+ + if (substr($backlink, 0, 1) eq '~') {
+ + return check_named_spec_existential($page, $backlink, \&match_backlink, @params);
+ + }
+ +
+ + return match_link($backlink, $page, @params);
+ }
+
+ sub match_created_before ($$;@) {
+ my $page=shift;
+ my $testpage=shift;
+ my %params=@_;
+ -
+ +
+ + if (substr($testpage, 0, 1) eq '~') {
+ + return check_named_spec_existential($page, $testpage, \&match_created_before, %params);
+ + }
+ +
+ $testpage=derel($testpage, $params{location});
+
+ if (exists $IkiWiki::pagectime{$testpage}) {
+ @@ -2014,6 +2108,10 @@ sub match_created_after ($$;@) {
+ my $testpage=shift;
+ my %params=@_;
+
+ + if (substr($testpage, 0, 1) eq '~') {
+ + return check_named_spec_existential($page, $testpage, \&match_created_after, %params);
+ + }
+ +
+ $testpage=derel($testpage, $params{location});
+
+ if (exists $IkiWiki::pagectime{$testpage}) {
--- a/IkiWiki/Plugin/edittemplate.pm
+++ b/IkiWiki/Plugin/edittemplate.pm
- @@ -46,8 +46,13 @@ sub preprocess (@) { #{{{
+ @@ -46,8 +46,13 @@ sub preprocess (@) {
$pagestate{$params{page}}{edittemplate}{$params{match}}=$params{template};
+ else {
+ return '';
+ }
- } # }}}
+ }
- sub formbuilder (@) { #{{{
+ sub formbuilder (@) {
--[[madduck]]
-[[tags wishlist patch]]
+[[!tags wishlist patch]]
+
+[[done]], though the patch I eventually applied uses "silent" as the
+parameter name. Sorry for forgetting about this patch until someone else
+implemented it too. --[[Joey]]
The [[typography_plugin|plugins/typography]] could support configuration of
-which translations to make. [[cpan Text::Typography]] supports fine-grained
+which translations to make. [[!cpan Text::Typography]] supports fine-grained
control of which translations to make, so [[plugins/typography]] just needs to
expose this somehow. --[[JoshTriplett]]
So I made a patch which unaccent chars: <http://users.itk.ppke.hu/~cstamas/code/ikiwiki/unaccentpagetitlenames/>
This is a one liner change, but requires a bit of reordering in the code.
-[[cstamas]]
+--[[cstamas]]
-[[tag wishlist patch]]
+> This was previously requested in [[todo/more_customisable_titlepage_function]],
+> in which [[Joey]] said "I don't think that changing titlepage is a good idea,
+> there are compatability problems".
+>
+> The problem is that altering titlepage changes the meaning of your wiki,
+> by resolving all wiki links to different page names. That means that:
+>
+> * unaccenting can't be automatic, it has to be a configuration option
+> (so you don't accidentally get different behaviour by installing
+> Text::Unaccent)
+> * upgrading Text::Unaccent becomes risky, as I doubt it guarantees to
+> have stable rules for how to transliterate into ASCII!
+>
+> --[[smcv]]
+
+[[!tag wishlist patch patch/core]]
--- /dev/null
+Many plugins seem to create temporary files. Although it is not much code, it is duplicated, and a
+typical place for security bugs. Would it be worthwhile to have library functions for creating temporary files
+and directories? If nothing else, it would serve as documentation of the "official way".
+
+Off to cut and paste :-) --[[DavidBremner]]
+
+> Hmm, I see only three users of temp files in all ikiwiki:
+> * hnb uses `File::Temp::mkstemp` to create two temp file handles.
+> * teximg uses `File::Temp::tempdir` to create a temporary directory.
+> * attachment retrieves a temp file from `CGI::tmpFileName`.
+> These are three quite different uses of temp files, not subject to
+> unification. Using `File::Temp` (and avoiding the posibly insecure
+> `mktemp`, `tmpname`, and `tempnam` functions) is probably as unified as
+> can be managed. --[[Joey]]
+
+>> OK, fair enough. Somehow the code in teximg made me think it was
+>> all a bit complicated. But after I played with it a bit more (and used File::Temp)
+>> I tend to agree, there is no real problem there to fix.
+>> Feel free to mark [[done]] [[DavidBremner]]
> I think you could now implement "toplvl" using [[conditionals|/plugins/conditional]]:
>
-> \[[if test="destpage(/index)" then="""...""" else="""..."""]]
+> \[[!if test="destpage(/index)" then="""...""" else="""..."""]]
>
> --[[JoshTriplett]]
> > directory, which is not very easy for a plain ol' user. Not everyone is the
> > sysadmin of their own machines with access to system dirs. --ManojSrivastava
+>>> It seems worth mentioning here that the `libdir` configuration parameter
+>>> lets you install additional plugins in a user-controlled directory
+>>> (*libdir*`/IkiWiki/Plugin`), avoiding needing root; indeed, a full local
+>>> ikiwiki installation without any involvement from the sysadmin is
+>>> [[possible|tips/DreamHost]]. --[[smcv]]
+
<pre>
varioki => {'motto' => '"Manoj\'s musings"',
'arrayvar' => '[0, 1, 2, 3]',
+=cut
+
+
-+sub import { #{{{
++sub import {
+ hook(type => "pagetemplate", id => "varioki", call => \&pagetemplate);
-+} # }}}
++}
+
+
+=pod
+
+=cut
+
-+sub pagetemplate (@) { #{{{
++sub pagetemplate (@) {
+ my %params=@_;
+ my $page=$params{page};
+ my $template=$params{template};
+ $template->param("$var" =>"$value");
+ }
+ }
-+} # }}}
++}
+
+1;
+
+
</pre>
-[[tag patch]]
+[[!tag patch]]
--- /dev/null
+It looks like all links in websites are absolute paths, this has some limitations:
+
+* If connecting to website via https://... all links will take you back to http://
+* Makes it harder to mirror website via HTML version, as all links have to be updated.
+
+It would be good if relative paths could be used instead, so the transport method isn't changed unless specifically requested.
+
+-- Brian May
+
+> Er, which absolute links are you talking about? If you view the source
+> to this page, you'll find links such as "../favicon.ico", "../style.css",
+> "../../", and "../". The only absolute links are to CGIs and the w3c DTD.
+> --[[Joey]]
+
+>> The problem is within the CGI script. The links within the HTML page are all absolute, including links to the css file.
+>> Having a http links within a HTML page retrieved using https upset most browsers (I think). Also if I push cancel on the edit page in https, I end up at at http page. -- Brian May
+
+>>> Ikiwiki does not hardcode http links anywhere. If you don't want
+>>> it to use such links, change your configuration to use https
+>>> consistently. --[[Joey]]
+
+Errr... That is not a solution, that is a work around. ikiwiki does not hard code the absolute paths, but absolute paths are hard coded in the configuration file. If you want to serve your website so that the majority of users can see it as http, including in rss feeds (this allows proxy caches to cache the contents and has reduced load requirements), but editing is done via https for increased security, it is not possible. I have some ideas how this can be implemented (as ikiwiki has the absolute path to the CGI script and the absolute path to the destination, it should be possible to generate a relative path from one to the other), although some minor issues still need to be resolved. -- Brian May
+
+I noticed the links to the images on <http://ikiwiki.info/recentchanges/> are also absolute, that is <http://ikiwiki.info/wikiicons/diff.png>; this seems surprising, as the change.tmpl file uses <TMPL_VAR BASEURL>
+which seems to do the right thing in page.tmpl, but not for change.tmpl. Where is BASEURL set? -- Brian May
+
+> The use of an absolute baseurl in change.tmpl is a special case. --[[Joey]]
+
+[[wishlist]]
--[[AdamShand]]
-[[tag wishlist]]
+[[!tag wishlist]]
-[[Wishlist]] item: I'd love to see the ability to optionally switch back to wiki syntax within the comments of code pretty-printed with the [[plugins/contrib/syntax]] plugin. This would allow the use of links and formatting in comments.
+[[Wishlist]] item: I'd love to see the ability to optionally switch back to
+wiki syntax within the comments of code pretty-printed with the
+[[plugins/contrib/syntax]] plugin. This would allow the use of links and
+formatting in comments.
+
+> You can do this using the [[plugins/highlight]] plugin, but you have
+> to explicitly put a format directive in the comment to do it. Thus,
+> I'm leaving this open for now.. ideally, comments would be detected,
+> and formatted as markdown. --[[Joey]]
--- /dev/null
+## summary
+at times it is useful to have a guided tour or trail through a subset of the pages of a wiki; in pmwiki, this is implemented as [wikitrails](http://www.pmwiki.org/wiki/PmWiki/WikiTrails).
+
+i'm working on a python xmlrpc plugin for ikiwiki to support wikitrails, both as a navigation feature (have "forward" and "back" links based on a sequence) and a modified inline that includes all pages in the trail with appropriate modifications (suitable for printing if necessary).
+
+the current status is published on `git://github.com/github076986099/ikiwiki-plugins.git`; as of now, i don't have a public demo of it.
+
+feedback on both the concept and the code is very much appreciated by [[discussion]] or [email](mailto:chrysn@fsfe.org).
+
+## usage
+
+two preprocessor commands are provided:
+
+### \[[!trail index="my_indexpage"]]
+
+embeds a navigation object with forward and back links as well as an indicator of the current position in the trail.
+
+if index is not specified, a suitable page up the path is used.
+
+this works very well together with the [[sidebar|plugins/sidebar]] plugin if the pages in a directory are roughly the same as the pages in the trail and the `index` is directory index page; just put the \[[!trail]] in the sidebar.
+
+### \[[!trailinclude index="my_indexpage"]]
+
+all pages linked from the index page are included in the same way as \[[!inline]] does, but in the proper sequence, with headings according to the indent in the source page and adoptions for the headings inside the page (a level 2 heading in a page that is a sub-sub-chapter in the whole trail will become a level 5 heading when trailincluded).
+
+## the index page
+
+the index page is parsed as markdown; numbered lists and "`*`" bulleted lists are discovered.
+
+## current issues
+
+ * rebuilding --- currently, there is no propper rebuilding of pages (will use `will_render` and `add_depends`). care has to be taken of how not yet created pages play into this.
+ * inline recursion --- there is simply no guard yet
+ * navigation layout --- has to be both flexible and usable-by-default
+ * heading shifting
+ * currently only works for markdown
+ * can break the limit of html's six heading levels
+ * search for index page is currently next to hardcoded
+ * reading the index --- markdown syntax parsing is currently on a it-can-use-what-i-produce level; maybe integrate with existing mdwn parser
+ * uses undocumented titlepage command
+ > Don't worry about that, titlepage isn't going anywhere, and will probably before a formal part of the api next time I consider api changes. --[[Joey]]
--- /dev/null
+This is a nice idea, I do have my gripes about the imeplementation.
+
+Assuming that the index's list is in mdwn format is not ideal. I guess the
+other way to do it would be to make the index be a directive, something
+like: \[[!trail pages="foo bar baz"]]. Assuming that a flat trail structure
+is enough, otherwise you'd have to get more fancy.
+
+The trailinclude seems a bit redundant with inline, and wanting to inline
+together all pages in a trail for printing or whatever seems like an
+unusual use case anyway?
+
+The !trail directive could be simplified to just \[[!trail my_indexpage]].
+But I wonder if needing to add this directive to every page is the best
+approach. Alternate approach would be to make the trail index cause
+breadcrums to be automatically inserted at the top of every page on the
+trail. (You'd have to use a directive to define the index for that to work.)
+
+--[[Joey]]
+
+----
+
+Revisiting this, after effectively reimplementing a small version of it
+in [[plugins/contrib/album]]: it occurs to me that might be a more
+"ikiwiki-like" way we could get this functionality.
+
+In the index page, you either want an [[ikiwiki/directive/inline]], or
+a list of links. In the former case, maybe we could extend inline like
+this:
+
+ \[[!inline ... blah blah ... trail=yes]]
+
+to make it remember the pages it inlined, in order, in the pagestate;
+in the latter case, we could replace the wikilinks with a directive,
+an operation something like this in diff notation:
+
+ - \[[one]] - the unit
+ - \[[two]] - the base of binary
+ - \[[three|3]] - is a crowd
+ + \[[!trailitem one]] - the unit
+ + \[[!trailitem two]] - the base of binary
+ + \[[!trailitem three|3]] - is a crowd
+
+and have that directive remember the pages in order.
+
+In both cases, a scan() hook could clear the list before starting to
+scan, then the inline or trailitem preprocessor directive could run in
+the scan stage as well as the render stage (in the case of inline,
+there'd be a very early return if trail=yes was not given, and
+an early return after collecting and sorting the pages if not
+actually rendering).
+
+This would mean that the contents of the trail, and a list of
+trails in which each page can be found, would already be in
+the pagestate by the time any page was rendered, so we'd be able
+to use them for output, either in a pagetemplate() hook or
+a \[[!trail]] preprocessor directive.
+
+This way, my album plugin could be turned inside out: instead
+of precomputing the pages to be inlined, then using
+[[pagenames|todo/inline plugin: specifying ordered page names]]
+to get them into the inline, it could just do the inline, then
+incorporate the output of \[[!trail]] into the template rendered
+for \[[!albumimage]] on each viewer page. (Also, the viewers
+wouldn't necessarily need to reference the album, only the other
+way round.)
+
+Using a pagetemplate() hook to stuff the next/previous links
+into page.tmpl would actually be a bit unfortunate for \[[!album]],
+because that plugin definitely wants to style the next/previous
+links as a thumbnail, which means there'd have to be a way to
+affect the style - perhaps by arranging for album's pagetemplate
+hook to run *after* trail's, or perhaps by having trail's
+pagetemplate hook disable itself for pages that contain
+a \[[!trail]] directive.
+
+I have now implemented this at [[plugins/contrib/trail]].
+What do you think? I'm still not sure how it would relate
+to [[plugins/contrib/album]], but if trail is reviewed
+and approved in principle, I'll try to adapt album as
+outlined above. --[[smcv]]
problem. According to the developers, it is possible to do that, and start
off in WikiText mode.
-[[tag soc]]
+[[!tag soc]]
-[[tag wishlist]]
+[[!tag wishlist]]
-[[tag patch]]
+[[!tag patch]]
Project IkiWiki::WIKIWYG v1.6 - <http://ikiwiki.xbaud.com/>
===========================================================
* Personalized settings
[Wikiwyg]: http://www.wikiwyg.net/
+
+> As noted in [[discussion]], the url above doesn't work, and I stupidly
+> lost my copy of this before merging it. I hope that this plugin will turn
+> back up. In the meantime, there is a wmd plugin that accomplishes the
+> same basic task of WSYWIG markdown editing. --[[Joey]]
I have to use the IkiWiki package instead of IkiWiki::Plugin::Wikiwyg? Or would a
better approach be to just copy that function into the Wikiwyg plugin?
* You can just call `IkiWiki::pagetitle()`.
+ > Note: pagetitle is now exported.
wikiwyg.tar.gz
If you want to translate your wiki into another language, there are
-essentailly three peices needed for a complete translation:
+essentially three pieces needed for a complete translation:
1. The messages in the ikiwiki program itself need to be translated.
Ikiwiki is internationalised, and most such messages are already marked
- with `gettext()`. THe source tarball includes a creates a `po/ikiwiki.pot`
+ with `gettext()`. The source tarball includes a `po/ikiwiki.pot`
that can be copied and translated as a po file. All very standard.
Note that a few things in the source are not currently translated. These
* The names and values of parameters, both to the program, in the setup
file, and in preprocessor directives.
+1. The [[basewiki]] needs to be translated. The
+ [[plugins/contrib/po]] ikiwiki plugin will allow translating
+ wikis using po files and can be used for this.
+
+ There is now a website, [l10n.ikiwiki.info](http://l10n.ikiwiki.info)
+ that both demos the translated basewiki, and allows easy translation of
+ it.
+
+ To generate the po and pot files for translating the basewiki,
+ get ikiwiki's source, edit the `po/underlay.setup` file,
+ adding your language. Then run 'make -C po underlays`.
+ This will generate many po files under `po/underlays`. The first
+ ones you'll want to translate are in the `po/underlays/basewiki` directory,
+ which is really not very large, just a few thousand words.
+ After that is done, you can tackle those under
+ `po/underlays/directives`, which are a much larger (tens of
+ thousands of words).
+
1. The templates also need to be translated. Some work has been done on an
infrastructure for maintaining translated templates, as documented in
[[todo/l10n]], but until that's complete, you'd need to copy and
translate the templates by hand.
-
-1. The [[basewiki]] itself needs to be translated. Whether to only translate
- the page contents, or also translate the page names, is an open
- question.
Maybe you should give write access to ikiwiki repository for translators
of PO files?
- > I recently set up a git repository mirroring the main svn repository (see
- > [[download]]) and one idea is that perhaps translators can use that for a
- > distributed revision control system that I can merge back from into svn.
- > I can set up accounts for svn, but as it's on my own personal server and
- > not a sourceforge/alioth like thing, it's a bit of a pain and maintenance
- > burden for me.
-
- >> OK, I've picked up Subversion for your ikiwiki, so I can get into
- >> Git now ;)
+ > We use git now, so you can clone my repo, commit to your clone, and
+ > use git to mail me patches. --[[Joey]]
3. What is the best way to update my PO file when you do some changes in
`ikiwiki.pot` file? Should I translate my PO file from scratch or
> size limits. This is generally done by adding comments in the pot file,
> and I've turned that on, and added a few. --[[Joey]]
->> Thank you very much! It also will be a big help for me. --[[Paweł|ptecza]]
\ No newline at end of file
+>> Thank you very much! It also will be a big help for me. --[[Paweł|ptecza]]
ikiwiki [options] source destination
-ikiwiki --setup configfile
+ikiwiki --setup setupfile
# DESCRIPTION
Force a rebuild of all pages.
+* --setup setupfile
+
+ In setup mode, ikiwiki reads the config file, which is really a perl
+ program that can call ikiwiki internal functions.
+
+ The default action when --setup is specified is to automatically generate
+ wrappers for a wiki based on data in a setup file, and rebuild the wiki.
+ If you only want to build any changed pages, you can use --refresh with
+ --setup.
+
+* --dumpsetup setupfile
+
+ Causes ikiwiki to write to the specified setup file, dumping out
+ its current configuration.
+
+* --wrappers
+
+ If used with --setup --refresh, this makes it also update any configured
+ wrappers.
+
* --cgi
Enable [[CGI]] mode. In cgi mode ikiwiki runs as a cgi script, and
Note that the generated wrapper will ignore all command line parameters.
-* --setup configfile
-
- In setup mode, ikiwiki reads the config file, which is really a perl
- program that can call ikiwiki internal functions.
-
- [[ikiwiki.setup]] is an example of such a config file.
-
- The default action when --setup is specified is to automatically generate
- wrappers for a wiki based on data in a config file, and rebuild the wiki.
- If you only want to build any changed pages, you can use --refresh with
- --setup.
-
-* --wrappers
-
- If used with --setup --refresh, this makes it also update any configured
- wrappers.
-
* --aggregate
If the [[plugins/aggregate]] plugin is enabled, this makes ikiwiki poll
# CONFIG OPTIONS
These options configure the wiki. Note that [[plugins]] can add additional
-configuration options of their own.
+configuration options of their own. All of these options and more besides can
+also be configured using a setup file.
-* --wikiname
+* --wikiname name
The name of the wiki, default is "wiki".
-* --templatedir
+* --templatedir dir
Specify the directory that the page [[templates|wikitemplates]] are stored in.
Default is `/usr/share/ikiwiki/templates`, or another location as configured at
ikiwiki. Old versions of templates do not always work with new ikiwiki
versions.
-* --underlaydir
+* --underlaydir dir
Specify the directory that is used to underlay the source directory.
Source files will be taken from here unless overridden by a file in the
* --rss, --norss
If rss is set, ikiwiki will default to generating RSS feeds for pages
- that inline a [[ikiwiki/blog]].
+ that inline a [[blog]].
* --allowrss
If allowrss is set, and rss is not set, ikiwiki will not default to
- generating RSS feeds, but setting `rss=yes` in the blog can override
- this default and generate a feed.
+ generating RSS feeds, but setting `rss=yes` in the inline directive can
+ override this default and generate a feed.
* --atom, --noatom
If atom is set, ikiwiki will default to generating Atom feeds for pages
- that inline a [[ikiwiki/blog]].
+ that inline a [[blog]].
* --allowatom
If allowatom is set, and rss is not set, ikiwiki will not default to
- generating Atom feeds, but setting `atom=yes` in the blog can override
- this default and generate a feed.
+ generating Atom feeds, but setting `atom=yes` in the inline directive can
+ override this default and generate a feed.
* --pingurl URL
* --prefix-directives, --no-prefix-directives
Toggle new '!'-prefixed syntax for preprocessor directives. ikiwiki currently
- defaults to --no-prefix-directives.
+ defaults to --prefix-directives.
* --w3mmode, --no-w3mmode
* --getctime
- Pull last changed time for each new page out of the revision control
+ Pull creation time for each new page out of the revision control
system. This rarely used option provides a way to get the real creation
times of items in weblogs, such as when building a wiki from a new
- Subversion checkout. It is unoptimised and quite slow. It is best used
+ VCS checkout. It is unoptimised and quite slow. It is best used
with --rebuild, to force ikiwiki to get the ctime for all pages.
* --set var=value
This allows setting an arbitrary configuration variable, the same as if it
- were set via a configuration file. Since most options can be configured
+ were set via a setup file. Since most options can be configured
using command-line switches, you will rarely need to use this, but it can be
useful for the odd option that lacks a command-line switch.
+# EXAMPLES
+
+* ikiwiki --setup my.setup
+
+ Completly (re)build the wiki using the specified setup file.
+
+* ikiwiki --setup my.setup --refresh
+
+ Refresh the wiki, using settings from my.setup, and avoid
+ rebuilding any pages that have not changed. This is faster.
+
+* ikiwiki --setup my.setup --refresh --wrappers
+
+ Refresh the wiki, including regnerating all wrapper programs,
+ but do not rebuild all pages. Useful if you have changed something
+ in the setup file that does not need a full wiki rebuild to update
+ all pages, but that you want to immediatly take effect.
+
# ENVIRONMENT
* CC
Joey Hess <joey@ikiwiki.info>
-Warning: this page is automatically made into ikiwiki's man page via [mdwn2man](http://ikiwiki.info/cgi-bin/viewvc.cgi/trunk/mdwn2man?root=ikiwiki&view=markup). Edit with care
+Warning: this page is automatically made into ikiwiki's man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD). Edit with care
List of users
=============
-[[inline pages="users/* and !users/*/* and !*/Discussion"
+[[!inline pages="users/* and !users/*/* and !*/Discussion"
feeds=no archive=yes sort=title template=titlepage
rootpage="users" postformtext="Add yourself as an ikiwiki user:"]]
--- /dev/null
+Running ikiwiki on her [homepage](http://spang.cc/) and [blog](http://blog.spang.cc/).
My watchlist:
-[[inline pages="todo/allow_wiki_syntax_in_commit_messages todo/shortcut_with_different_link_text" archive="yes" sort="mtime" atom="yes"]]
+[[!inline archive="yes" sort="mtime" atom="yes" pages="
+todo/allow_wiki_syntax_in_commit_messages*
+todo/shortcut_with_different_link_text*
+todo/structured_page_data*
+tips/convert_mediawiki_to_ikiwiki*
+"]]
--- /dev/null
+<http://www.sgenomics.org/~jtang>
-[[meta title="Karl Mowatt-Wilson"]]
+[[!meta title="Karl Mowatt-Wilson"]]
Working on an [asciidoc](http://www.methods.co.nz/asciidoc/) plugin for ikiwiki so I can use it for my [website](http://mowson.org/karl), where I'm documenting how to run linux on the HP/Compaq Evo T20 'thin client'.
\ No newline at end of file
--- /dev/null
+It feels like there are a lot of people named Steven Black. While I'm just one of many with my name, sometimes it is actually just me and I've forgotten that I had an account somewhere.
+
+I'm not a doctor, though I would certainly trust any doctor, dentist, or philosopher named Steven Black. (There are several.)
+
+I *am* a huge Ikiwiki fan. I've had my eye on it for many years for personal projects (though I never quite got around to installing it). Recently, however, I managed to convince my coworkers that it would be a good idea for an internal wiki. Boy was I right. The thing is practically designed to be the perfect developer-centered wiki.
-[[meta title="Taylor Killian"]]
+[[!meta title="Taylor Killian"]]
Hi,
--- /dev/null
+<http://bosboot.org>
--- /dev/null
+Hey... I'm just starting to use ikiwiki, but am happy to find it repeatedly doing the sorts of things in a way which makes sense to me. (e.g. most pages are static, DVCS for file store etc.)
--- /dev/null
+I started using Ikiwiki as a way to replace [Trac](http://trac.edgewall.org/) when using [Monotone](http://monotone.ca/). Version control has been an interest of mine for a while and I wrote most of the ikiwiki [[rcs/monotone]] plugin. I'm not actively working on the Monotone plugin any more.
+
+Lately I've been using Ikiwiki for other things and seem to be scratching a few itches here and there. :)
+
+I generally use my [[ikiwiki/openid]] login when editing here: <http://www.cse.unsw.edu.au/~willu/>
+
+Generic License Grant
+-----------------
+
+Unless otherwise specified, any code that I post to this wiki I release under the GPL2+. Any non-code patches I post are released under [[standard ikiwiki licenses|freesoftware]].
+
+------
+
+### Open Bugs:
+
+[[!inline pages="link(users/Will) and bugs/* and !bugs/done and !bugs/discussion and !link(patch) and !link(bugs/done) and !bugs/*/*" archive="yes" feeds="no" ]]
+
+### Open ToDos:
+
+[[!inline pages="link(users/Will) and todo/* and !todo/done and !todo/discussion and !link(patch) and !link(todo/done) and !bugs/*/*" archive="yes" feeds="no" ]]
+
+### Unapplied Patches:
+
+[[!inline pages="link(users/Will) and (todo/* or bugs/*) and !bugs/done and !bugs/discussion and !todo/done and !todo/discussion and link(patch) and !link(bugs/done) and !link(todo/done) and !bugs/*/*" archive="yes" feeds="no" ]]
-[[meta title="Adam Shand"]]
+[[!meta title="Adam Shand"]]
New IkiWiki user, long time wiki user. :-)
--- /dev/null
+[[!meta title="Adam Trickett"]]
+
+# Adam Trickett
+
+## "ajt"
+
+I'm a long time hacker of sorts, I like to program in Perl on Debian systems but work pays me to program in ABAP (COBOL) on SAP.
+
+I like wikis and I'm currently in love with ikiwiki, having moved my home intranet from a home made template solution to ikiwiki over a weekend. I'm using ikiwiki more like a web content management system (e.g. RedDot) rather than a traditional wiki.
+
+### My Links
+
+* [iredale dot net](http://www.iredale.net/) my web server and main blog
+* [ajt](http://www.perlmonks.org/index.pl?node_id=113686) my Perkmonks home node
+* [ajt](http://use.perl.org/~ajt) my use Perl home
+* [ATRICKETT](http://search.cpan.org/~atrickett/) my CPAN folder
+* [ajt](http://www.debian-administration.org/users/ajt) my Debian-Administration home (good site btw)
+* [drajt](http://www.linkedin.com/in/drajt) my LinkedIn profile
+* [drajt](http://www.slideshare.net/drajt) my "Slidespace" on SlideShare
+* [AdamTrickett](http://www.hants.lug.org.uk/cgi-bin/wiki.pl?AdamTrickett) my wiki page on my LUG's site
--- /dev/null
+I use ikiwiki to organize information - projects, reading notes, outlines, todo lists, etc.
-[[meta title="Arpit Jain"]]
+[[!meta title="Arpit Jain"]]
Hi,
I am Arpit Jain. I am final year B.Tech/M.Tech(Dual Degree) student at Department of Computer Science and Engineering, Indian Institute of Technology, Kharagpur.
-[[meta title="Bruno Beaufils"]]
+[[!meta title="Bruno Beaufils"]]
Bruno Beaufils is **<bruno@boulgour.com>**.
--- /dev/null
+Brian St. Pierre is **<brian@bstpierre.org>**
--- /dev/null
+I maintain a [home page](http://www.panix.com/~cfm/ "Cory Myers").
-[[meta title="Chris Green"]]
+[[!meta title="Chris Green"]]
Chris is Chris Green, an ancient C/C++/Java programmer, I started around 1982 or 1983.
--- /dev/null
+http://Cord.de
-[[meta title="Adeodato Simó"]]
+[[!meta title="Adeodato Simó"]]
<http://chistera.yi.org/~adeodato>
--- /dev/null
+<http://www.larted.org.uk/~dom>
+
+Just another ikiwiki user.
--- /dev/null
+Don Marti home page: <http://zgp.org/~dmarti/> email: <dmarti@zgp.org>
+
--- /dev/null
+Using ikiwiki for my yet to be publish personal website :)
-[[meta title="Thomas Harning Jr"]]
+[[!meta title="Thomas Harning Jr"]]
I began using ikiwiki since it ties into git... and so far it's working great!
-[[meta title="Hugues Bernard"]]
+[[!meta title="Hugues Bernard"]]
For now I'm using ikiwiki just for my personal needs :
I'd love to see any notes you have on using ikiwiki for GTD. Would you
consider documenting them? Perhaps we could turn the result into a
[[tip|tips]]. -[[JoshTriplett]]
-> Well, certainly. Basically it's just inline + tag feature. I'm going to have more time in May for ikiwiki, I hope.
\ No newline at end of file
+> Well, certainly. Basically it's just inline + tag feature. I'm going to have more time in May for ikiwiki, I hope.
+> > Any news about that ?
--- /dev/null
+[Kai Hendry](http://hendry.iki.fi/)
--- /dev/null
+intrigeri AT boum.org, already loving ikiwiki.
+
+* [gnupg key](http://gaffer.ptitcanardnoir.org/intrigeri/intrigeri.asc)
+* Git repository with various ikiwiki {feature, bugfix}-branches : `git://gaffer.ptitcanardnoir.org/ikiwiki.git`
+[[!meta title="Jason Blevins"]]
+
I'm currently hosting a private ikiwiki for keeping research notes
-which, with some patches and a (currently unreleased) plugin, will
-convert inline LaTeX expressions to MathML. I'm working towards a
+which, with some patches and a plugin (below), will
+convert inline [[todo/LaTeX]] expressions to [[MathML]]. I'm working towards a
patchset and instructions for others to do the same.
-There is one thing that needs to be decided first: whether or not to
-include [[sanitization|todo/svg]] of MathML in htmlscrubber (and while
-we're at it, why not SVG).
+I've setup a test ikiwiki [here](http://xbeta.org/colab/) where I've
+started keeping a few notes on my progress. There is an example of
+inline [[todo/SVG]] on the homepage (note that the logo scales along with the
+font size). There are a few example mathematical expressions in the
+[sandbox](http://xbeta.org/colab/sandbox/). The MathML is generated
+automatically from inline LaTeX expressions using an experimental
+plugin I'm working on.
My (also MathML-enabled) homepage: <http://jblevins.org/> (still using
Blosxom...maybe one day I'll convert it to ikiwiki...)
+
+Current ikiwki issues of interest:
+
+ * [[bugs/recentchanges_feed_links]]
+ * [[bugs/HTML_inlined_into_Atom_not_necessarily_well-formed]]
+ * [[plugins/toc/discussion]]
+ * [[todo/BibTeX]]
+ * [[todo/svg]]
+ * [[todo/Option_to_make_title_an_h1?]]
+ * [[bugs/SVG_files_not_recognized_as_images]]
+
+## Plugins
+
+These plugins are experimental. Use them at your own risk. Read the
+perldoc documentation for more details. Patches and suggestions are
+welcome.
+
+ * [mdwn_itex][] - Works with the [[`mdwn`|plugins/mdwn]] plugin to convert inline [[todo/LaTeX]]
+ expressions to [[MathML]] using `itex2MML`.
+
+ * [h1title][] - If present, use the leading level 1 Markdown header to
+ set the page title and remove it from the page body.
+
+ * [code][] - Whole file and inline code snippet [[todo/syntax highlighting]]
+ via GNU Source-highlight. The list of supported file extensions is
+ configurable. There is also some preliminary [documentation][code-doc].
+ See the [FortranWiki](http://fortranwiki.org) for examples.
+
+ * [metamail][] - a plugin for loading metadata from [[email]]-style
+ headers at top of a file (e.g., `title: Page Title` or
+ `date: November 2, 2008 11:14 EST`).
+
+ * [pandoc][] - [[ikiwiki/Markdown]] page processing via [Pandoc](http://johnmacfarlane.net/pandoc/) (a Haskell library for converting from one markup format to another). [[todo/LaTeX]] and
+ [[reStructuredText|plugins/rst]] are optional.
+
+ * [path][] - Provides path-specific template conditionals such as
+ `IS_HOMEPAGE` and `IN_DIR_SUBDIR`.
+
+ [mdwn_itex]: http://code.jblevins.org/ikiwiki/plugins.git/plain/mdwn_itex.pm
+ [h1title]: http://code.jblevins.org/ikiwiki/plugins.git/plain/h1title.pm
+ [code]: http://code.jblevins.org/ikiwiki/plugins.git/plain/code.pm
+ [code-doc]: http://code.jblevins.org/ikiwiki/plugins.git/plain/code.text
+ [metamail]: http://code.jblevins.org/ikiwiki/plugins.git/plain/metamail.pm
+ [pandoc]: http://code.jblevins.org/ikiwiki/plugins.git/plain/pandoc.pm
+ [path]: http://code.jblevins.org/ikiwiki/plugins.git/plain/path.pm
+
+
+## MathML and SVG support
+
+So far, I've made some notes on sanitizing MathML and SVG via
+htmlscrubber on the [[todo/svg]] todo item.
+
+I've also worked out some content-negotiation issues. First of all,
+one needs to modify the default templates to use the
+XHTML+MathML+SVG doctype (see e.g., this [patch][template-patch]).
+For most browsers, the content type of the pages should be
+`application/xhtml+xml`. The solution is easy if you want to
+just send `application/xhtml+xml` to everybody:
+just change the content type of `.html` files across the board.
+
+However, if you want to support browsers that don't accept
+`application/xhtml+xml` (and those that will but say they
+don't, such as IE with the MathPlayer plugin), then one
+needs a `mod_rewrite` rule like the following:
+
+ RewriteCond %{HTTP_ACCEPT} application\/xhtml\+xml [OR]
+ RewriteCond %{HTTP_USER_AGENT} (W3C.*Validator|MathPlayer)
+ RewriteRule \.html$ - [T=application/xhtml+xml]
+
+This solves the problem of MathML and inline SVG in static pages
+but some additional work is required for dynamically generated
+pages, like page previews, that are generated by `ikiwiki.cgi`.
+We need to allow `ikiwiki.cgi` to set the content type dynamically
+based on the `HTTP_CONTENT_TYPE` environment variable
+(e.g., with the following [patch][cgi-patch]). Then, the following
+rewrite rules can pass the correct content type to ikiwiki:
+
+ RewriteCond %{HTTP_ACCEPT} application\/xhtml\+xml [OR]
+ RewriteCond %{HTTP_USER_AGENT} (W3C.*Validator|MathPlayer)
+ RewriteRule ikiwiki.cgi$ - [T=application/xhtml+xml]
+
+One final critical issue is that a production-ready setup needs to
+implement some sort of on-the-fly error handling. If a user submits
+an invalid LaTeX expression or SVG code (not malicious, just invalid)
+and saves the page, then browsers like Firefox will halt processing of
+the page, preventing any further viewing or editing. A less than
+optimal solution is to force users to preview the page before saving.
+That way if someone introduces invalid XHTML then they can't save the
+page in the first place (unless they post directly to the right URL).
+
+ [template-patch]: http://xbeta.org/gitweb/?p=xbeta/ikiwiki.git;a=blobdiff;f=templates/page.tmpl;h=380ef699fa72223744eb5c1ee655fb79aa6bce5b;hp=9084ba7e11e92a10528b2ab12c9b73cf7b0f40a7;hb=416d5d1b15b94e604442e4e209a30dee4b77b684;hpb=ececf4fb8766a4ff7eff943b3ef600be81a0df49
+ [cgi-patch]: http://xbeta.org/gitweb/?p=xbeta/ikiwiki.git;a=commitdiff;h=fa538c375250ab08f396634135f7d79fce2a9d36
--- /dev/null
+[Jelmer Vernooij](http://samba.org/~jelmer/)
-[[meta title="Jeremy Reed"]]
+[[!meta title="Jeremy Reed"]]
I am testing ikiwiki. I made a RCS plugin.
\ No newline at end of file
-[[meta title="Joey Hess"]]
+[[!meta title="Joey Hess"]]
Joey Hess is <a href="mailto:joey@kitenet.net">joey@kitenet.net</a>.
His web page is [here](http://kitenet.net/~joey/).
--- /dev/null
+I'm looking at Ikiwiki, searching the best Wiki. The only other one I've found is [werc](http://werc.cat-v.org/).
+
+email: `jogo matabio net`.
--- /dev/null
+[[!meta title="Jon Dowland"]]
+I'm looking at ikiwiki both for my personal site but also as a
+team-documentation management system for a small-sized group of UNIX
+sysadmins.
+
+* my edits should appear either as 'Jon' (if I've used
+ [[tips/untrusted_git_push]]) or 'jmtd.net' (or once upon a time
+ 'alcopop.org/me/openid/' or 'jondowland').
+* My [homepage](http://jmtd.net/) is powered by ikiwiki
+
+I gave a talk at the [UK UNIX User's Group](http://www.ukuug.org/) annual
+[Linux conference](http://www.ukuug.org/events/linux2008/) about organising
+system administrator documentation. Roughly a third of this talk was
+discussing IkiWiki in some technical detail and suggesting it as a good piece
+of software for this task.
+
+ * slides at <http://www.staff.ncl.ac.uk/jon.dowland/unix/docs/>.
+
+I am also working on some ikiwiki hacks:
+
+* an alternative approach to [[plugins/comments]] (see
+ [[todo/more flexible inline postform]] for one piece of the puzzle;
+ <http://dev.jmtd.net/comments/> for some investigation into making the post
+ form more integrated)
+* a system for [[forum/managing_todo_lists]] (see also
+ [[todo/interactive todo lists]] and <http://dev.jmtd.net/outliner/> for the
+ current WIP).
-[[meta title="Jonas Smedegaard"]]
+[[!meta title="Jonas Smedegaard"]]
Jonas Smedegaard is a Debian developer, like joey. A big fan of this novel approach to wiki: serving as pages static!
+++ /dev/null
-A new ikiwiki user, looking at ikiwiki both for his personal site but also as a team-documentation management system for a small-sized group of UNIX sysadmins.
-
-* (currently non-ikiwiki) Homepage: <http://alcopop.org/>
-* potential future (ikiwiki) Homepage: <http://jmtd.net/>
--- /dev/null
+Joseph Turian is a scientist. You can email him at
+ lastname at gmail dot com
+
+* Academic: <http://www-etud.iro.umontreal.ca/~turian/>
+
+He hopes to set up ikiwiki and organize his thoughts.
+
+He also imagines adding wacky NLP and machine learning to ikiwiki.
+
+In more hazy dreams, he hopes that ikiwiki is someday ported to python.
-[[meta title="Josh Triplett"]]
+[[!meta title="Josh Triplett"]]
-Josh Triplett; `josh@{freedesktop.org,kernel.org,psas.pdx.edu}`.
+Email: `josh@{joshtriplett.org,freedesktop.org,kernel.org,psas.pdx.edu}`.
+
+[Josh Triplett's homepage](http://joshtriplett.org)
Proud user of ikiwiki.
-Currently working on scripts to convert MoinMoin and TWiki wikis to ikiwikis
-backed by a git repository, including full history.
+Currently working on scripts to convert MoinMoin and TWiki wikis to
+ikiwikis backed by a git repository, including full history.
+Available from the following repositories, though not well-documented:
-> I've written about how I converted from Mediawiki here: <http://iki.u32.net/Mediawiki_Conversion/> Are you ever going to release your scripts? --[[sabr]]
+ git clone git://svcs.cs.pdx.edu/git/wiki2iki/moin2iki
+ git clone git://svcs.cs.pdx.edu/git/wiki2iki/html-wikiconverter
+ git clone git://svcs.cs.pdx.edu/git/wiki2iki/twiki
--- /dev/null
+[[!meta redir=users/jasonblevins]]
--- /dev/null
+Jan Walzer started to look on ikiwiki just recently.
+
+Read [here](http://wa.lzer.net/wiki/ikiwiki/whyikiwiki/) why he uses ikiwiki.
-[[meta title="Kyle MacLea"]]
+[[!meta title="Kyle MacLea"]]
[Kyle MacLea](http://kitenet.net/~kyle) was an early adopter of **ikiwiki**. He really likes it, especially for his [FamilyWiki](http://kitenet.net/~kyle/family/wiki) and [Emigration Registry](http://kitenet.net/~kyle/family/registry).
\ No newline at end of file
I track this site with the following feed:
-[[inline pages="internal(recentchanges/change_*) and !author(http://madduck.net/)"
+[[!inline pages="internal(recentchanges/change_*) and !author(http://madduck.net/)"
feedonly=yes atom=no]]
-[[meta title="Marcelo E. Magallon"]]
+[[!meta title="Marcelo E. Magallon"]]
Marcelo E. Magallon <marcelo dot magallon in Google Mail>
\ No newline at end of file
--- /dev/null
+I used IkiWiki to supplant some custom journal software. I like that it uses
+the filesystem, my intent is to make journal entries as future-proof as
+possible. I'll probably start using it for generation of entire sites, soon.
+
+Things generated by IkiWiki with some fancypants stylesheets:
+
+* [woozle.org](http://woozle.org/)
+* [My page](http://woozle.org/~neale/)
+* [Amy's blog](http://woozle.org/~aim/blog/)
+* [Heidi's blog](http://woozle.org/~heidi/blog/)
--- /dev/null
+Hi, I'm Nolan. I'll add more later.
-[[meta title="Per Olofsson"]]
+[[!meta title="Per Olofsson"]]
Per Olofsson
-[[meta title="Paweł Tęcza"]]
+[[!meta title="Paweł Tęcza"]]
My name is Paweł Tęcza. Currently I work as mail system administrator,
C/Perl programmer and computer projects designer at Warsaw University, Poland.
than Debian and I don't want to wait more then 1 year for new stable
release.
-I'm also author of ikiwiki backports for Debian 'sarge'. You can find
-this and another my backports at
-[public GPA's Debian packages archive](http://gpa.net.icm.edu.pl/debian/).
+I'm also author of unofficial ikiwiki backports. In the past I was
+rebuilding ikiwiki source package for Debian Sarge and Ubuntu Gutsy.
+Now I do the same for Ubuntu Hardy. You can find this and another
+my backports at [public GPA's Ubuntu packages archive](http://gpa.net.icm.edu.pl/ubuntu/).
+
+I love using Ikiwiki and bug reporting ;)
-[[toc ]]
+[[!toc ]]
### My name
Thanks to [[madduck]], I track this site with the following feed:
-[[inline pages="internal(recentchanges/change_*) and !author(http://sabr.myopenid.com/)"
+[[!inline pages="internal(recentchanges/change_*) and !author(http://sabr.myopenid.com/)"
feedonly=yes rss=no atom=yes]]
### Tests
--- /dev/null
+[Amitai Schlair](http://www.columbia.edu/~ays2105/) recently discovered ikiwiki and finds himself using it for all sorts of things. His attempts at contributing:
+
+[[!map pages="link(users/schmonz) and plugins/* and !*/Discussion"]]
--- /dev/null
+seanh is an ikiwiki user.
--- /dev/null
+## personal/site info
+
+New ikiwiki site at my web site, blog, kisikew.org home site, for indigenews, and our indigenous-centric wiki (mostly East Coast/Woodlands area). Mediawiki stuff was imported successfully (as noted on this web site).
+
+## ikiwiki branch at github
+
+Maintain my own branch, partly to learn about VCS, git, ikiwiki, Debian packaging, and Perl. I don't recommend anyone pull from it, as I use third-party plugins included on this site that people may not want in a default installation of ikiwiki. This is why I don't push to Joey's -- so it's nothing personal, I just don't want to mess things up for other people, from my mistakes and stumbles.
+
--- /dev/null
+Website: [pseudorandom.co.uk](http://www.pseudorandom.co.uk/)
+
+Blog: [smcv.pseudorandom.co.uk](http://smcv.pseudorandom.co.uk/)
+
+My repository containing ikiwiki branches:
+
+* gitweb: http://git.pseudorandom.co.uk/smcv/ikiwiki.git
+* anongit: git://git.pseudorandom.co.uk/git/smcv/ikiwiki.git
+
+Currently thinking about a [[users/smcv/gallery]] plugin.
--- /dev/null
+This plugin has now been implemented as [[plugins/contrib/album]]; this
+page has older thoughts about it.
+
+## Requirements
+
+This plugin formats a collection of images into a photo gallery,
+in the same way as many websites: good examples include the
+PHP application [Gallery](http://gallery.menalto.com/), Flickr,
+and Facebook's Photos "application".
+
+The web UI I'm trying to achieve consists of one
+[HTML page of thumbnails](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/)
+as an entry point to the gallery, where each thumbnail links to
+[a "viewer" HTML page](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/img_0068/)
+with a full size image, next/previous thumbnail links, and
+[[plugins/comments]].
+
+(The Summer of Code [[plugins/contrib/gallery]] plugin does the
+next/previous UI in Javascript using Lightbox, which means that
+individual photos can't be bookmarked in a meaningful way, and
+the best it can do as a fallback for non-Javascript browsers
+is to provide a direct link to the image.)
+
+Other features that would be good to have:
+
+* minimizing the number of separate operations needed to make a gallery -
+ editing one source file per gallery is acceptable, editing one
+ source file per photo is not
+
+* keeping photos outside source code control, for instance in an
+ underlay
+
+* assigning [[tags|ikiwiki/directive/tag]] to photos, providing a
+ superset of Facebook's "show tagged photos of this person" functionality
+
+* constructing galleries entirely via the web by uploading attachments
+
+* inserting grouping (section headings) within a gallery; as in the example
+ linked above, I'd like this to split up the thumbnails but not the
+ next/previous trail
+
+* rendering an `<object>/<embed>` arrangement to display videos, and possibly
+ thumbnailing them in the same way as totem-video-thumbnailer
+ (my camera can record short videos, so some of my web photo galleries
+ contain them)
+
+My plan is to have these directives:
+
+* \[[!gallery]] registers the page it's on as a gallery, and displays all
+ photos that are part of this gallery but not part of a \[[!gallerysection]]
+ (below).
+
+ All images (i.e. `*.png *.jpg *.gif`) that are attachments to the gallery page
+ or its subpages are considered to be part of the gallery.
+
+ Optional arguments:
+
+ * filter="[[ikiwiki/PageSpec]]": only consider images to be part of the
+ gallery if they also match this filter
+
+ * sort="date|filename": order in which to sort the images
+
+* \[[!gallerysection filter="[[ikiwiki/PageSpec]]"]] displays all photos in the
+ gallery that match the filter
+
+So,
+[the gallery I'm using as an example](http://www.pseudorandom.co.uk/2008/2008-03-08-panic-cell-gig/)
+could look something like this:
+
+ \[[!gallery]]
+ <!-- replaced with one uncategorized photo -->
+
+ # Gamarra
+
+ \[[!gallerysection filter="link(sometag)"]]
+ <!-- all the Gamarra photos -->
+
+ # Smokescreen
+
+ \[[!gallerysection filter="link(someothertag)"]]
+ <!-- all the Smokescreen photos -->
+
+ <!-- ... -->
+
+## Implementation ideas
+
+The next/previous part this plugin overlaps with [[todo/wikitrails]].
+
+A \[[!galleryimg]] directive to assign metadata to images might be necessary, so
+the gallery page can contain something like:
+
+ \[[!galleryimg p1010001.jpg title="..." caption="..." tags="foo"]]
+ \[[!galleryimg p1010002.jpg title="..." caption="..." tags="foo bar"]]
+
+However, allowing other pages to push in metadata like that will make
+dependency tracking difficult.
+
+Making the viewer pages could be rather tricky. Here are some options:
+"synthesize source pages for viewers" is the one I'm leaning towards at the
+moment.
+
+### Viewers' source page is the gallery
+
+One possibility is to write out the viewer pages as a side-effect of
+preprocessing the \[[!gallery]] directive. The proof-of-concept implementation
+below does this. However, this does mean the viewer pages can't have tags or
+metadata of their own and can't be matched by [[pagespecs|ikiwiki/pagespec]] or
+[[wikilinks|ikiwiki/wikilink]].
+
+It might be possible to implement tagging by using \[[!galleryimg]] to assign
+the metadata to the *images* instead of their viewers; however, that would
+require hacking up both `IkiWiki::htmllink` and `IkiWiki::urlto` to redirect
+links to the image (e.g. from the \[[!map]] on a tag page) to become links to
+the viewer page.
+
+Modifications to the comments plugin would also be required, to make it allow
+comments written to `foo/bar/comment_1._comment` even though the page foo/bar
+does not really exist, and display comments on the viewer pages even though
+they're not real pages. (Writing comments to `foo/bar.jpg/*._comment` is not
+an option!)
+
+### Synthesize source pages for viewers
+
+(Edited to add: this is what [[plugins/contrib/album]] implements. --[[smcv]])
+
+Another is to synthesize source pages for the viewers. This means they can have
+tags and metadata, but trying to arrange for them to be scanned etc. correctly
+without needing another refresh run is somewhat terrifying.
+[[plugins/autoindex]] can safely create source pages because it runs in
+the refresh hook, but I don't really like the idea of a refresh hook that scans
+all source pages to see if they contain \[[!gallery]]...
+
+The photo galleries I have at the moment, like the Panic Cell example above,
+are made by using an external script to parse XML gallery descriptions (lists
+of image filenames, with metadata such as titles), and using this to write
+IkiWiki markup into a directory which is then used as an underlay. This is a
+hack, but it works. The use of XML is left over from a previous attempt at
+solving the same problem using Django.
+
+Perhaps a better approach would be to have a setupfile option that names a
+particular underlay directory (meeting the objective of not having large
+photos under source code control) and generates a source page for each file
+in that directory during the refresh hook. The source pages could be in the
+underlay until they are edited (e.g. tagged), at which point they would be
+copied into the source-code-controlled version in the usual way.
+
+> Coming back to this: a specialized web UI to mark attachments as part of
+> the gallery would make this easy too - you'd put the photos in the
+> underlay, then go to the CGI and say "add all". --[[smcv]]
+
+The synthetic source pages can be very simple, using the same trick as my
+[[plugins/comments]] plugin (a dedicated [[directive|ikiwiki/directives]]
+encapsulating everything the plugin needs). If the plugin automatically
+gathers information like file size, pixel size, date etc. from the images, then
+only the human-edited information and a filename reference need to be present
+in the source page; with some clever lookup rules based on the filename of
+the source page, not even the photo's filename is necessarily needed.
+
+> Coming back to this later: the clever lookup rules make dependency tracking
+> hard, though. --[[smcv]]
+
+ \[[!meta title="..."]]
+ \[[!meta date="..."]]
+ \[[!meta copyright="..."]]
+ \[[!tag ...]]
+
+ \[[!galleryimageviewer p1010001.jpg]]
+
+However, this would mean that editing tags and other metadata would require
+editing pages individually. Rather than trying to "fix" that, perhaps it would
+be better to have a special CGI interface for bulk tagging/metadata editing.
+This could even be combined with a bulk upload form (a reasonable number of
+file upload controls - maybe 20 - with metadata alongside each).
+
+Uploading multiple images is necessarily awkward due to restrictions placed on
+file upload controls by browsers for security reasons - sites like Facebook
+allow whole directories to be uploaded at the same time, but they achieve this
+by using a signed Java applet with privileged access to the user's filesystem.
+
+I've found that it's often useful to be able to force the creation time of
+photos (my camera's battery isn't very reliable, and it frequently decides that
+the date is 0000-00-00 00:00:00), so treating the \[[!meta date]] of the source
+page and the creation date of the photo as synonymous would be useful.
+
+### Images are the viewer's source - special filename extension
+
+Making the image be the source page (and generate HTML itself) would be
+possible, but I wouldn't want to generate a HTML viewer for every `.jpg` on a
+site, so either the images would have to have a special extension (awkward for
+uploads from Windows users) or the plugin would have to be able to change
+whether HTML was generated in some way (not currently possible).
+
+### Images are the viewer's source - alter `ispage()`
+
+It might be possible to hack up `ispage()` so some, but not all, images are
+considered to "be a page":
+
+* srcdir/not-a-photo.jpg → destdir/not-a-photo.jpg
+* srcdir/gallery/photo.jpg → destdir/gallery/photo/index.html
+
+Perhaps one way to do this would be for the photos to appear in a particular
+underlay directory, which would also fulfil the objective of having photos not
+be version-controlled:
+
+* srcdir/not-a-photo.jpg → destdir/not-a-photo.jpg
+* underlay/gallery/photo.jpg → destdir/gallery/photo/index.html
+
+## Proof-of-concept implementation of "viewers' source page is the gallery"
+
+ #!/usr/bin/perl
+ package IkiWiki::Plugin::gallery;
+
+ use warnings;
+ use strict;
+ use IkiWiki 2.00;
+
+ sub import {
+ hook(type => "getsetup", id => "gallery", call => \&getsetup);
+ hook(type => "checkconfig", id => "gallery", call => \&checkconfig);
+ hook(type => "preprocess", id => "gallery",
+ call => \&preprocess_gallery, scan => 1);
+ hook(type => "preprocess", id => "gallerysection",
+ call => \&preprocess_gallerysection, scan => 1);
+ hook(type => "preprocess", id => "galleryimg",
+ call => \&preprocess_galleryimg, scan => 1);
+ }
+
+ sub getsetup () {
+ return
+ plugin => {
+ safe => 1,
+ rebuild => undef,
+ },
+ }
+
+ sub checkconfig () {
+ }
+
+ # page that is a gallery => array of images
+ my %galleries;
+ # page that is a gallery => array of filters
+ my %sections;
+ # page that is an image => page name of generated "viewer"
+ my %viewers;
+
+ sub preprocess_gallery {
+ # \[[!gallery filter="!*/cover.jpg"]]
+ my %params=@_;
+
+ my $subpage = qr/^\Q$params{page}\E\//;
+
+ my @images;
+
+ foreach my $page (keys %pagesources) {
+ # Reject anything not a subpage or attachment of this page
+ next unless $page =~ $subpage;
+
+ # Reject non-images
+ # FIXME: hard-coded list of extensions
+ next unless $page =~ /\.(jpg|gif|png|mov)$/;
+
+ # Reject according to the filter, if any
+ next if (exists $params{filter} &&
+ !pagespec_match($page, $params{filter},
+ location => $params{page}));
+
+ # OK, we'll have that one
+ push @images, $page;
+
+ my $viewername = $page;
+ $viewername =~ s/\.[^.]+$//;
+ $viewers{$page} = $viewername;
+
+ my $filename = htmlpage($viewername);
+ will_render($params{page}, $filename);
+ }
+
+ $galleries{$params{page}} = \@images;
+
+ # If we're just scanning, don't bother producing output
+ return unless defined wantarray;
+
+ # actually render the viewers
+ foreach my $img (@images) {
+ my $filename = htmlpage($viewers{$img});
+ debug("rendering image viewer $filename for $img");
+ writefile($filename, $config{destdir}, "# placeholder");
+ }
+
+ # display a list of "loose" images (those that are in no section);
+ # this works because we collected the sections' filters during the
+ # scan stage
+
+ my @loose = @images;
+
+ foreach my $filter (@{$sections{$params{page}}}) {
+ my $_;
+ @loose = grep { !pagespec_match($_, $filter,
+ location => $params{page}) } @loose;
+ }
+
+ my $_;
+ my $ret = "<ul>\n";
+ foreach my $img (@loose) {
+ $ret .= "<li>";
+ $ret .= "<a href=\"" . urlto($viewers{$img}, $params{page});
+ $ret .= "\">$img</a></li>\n"
+ }
+ return "$ret</ul>\n";
+ }
+
+ sub preprocess_gallerysection {
+ # \[[!gallerysection filter="friday/*"]]
+ my %params=@_;
+
+ # remember the filter for this section so the "loose images" section
+ # won't include these images
+ push @{$sections{$params{page}}}, $params{filter};
+
+ # If we're just scanning, don't bother producing output
+ return unless defined wantarray;
+
+ # this relies on the fact that we ran preprocess_gallery once
+ # already, during the scan stage
+ my @images = @{$galleries{$params{page}}};
+ @images = grep { pagespec_match($_, $params{filter},
+ location => $params{page}) } @images;
+
+ my $_;
+ my $ret = "<ul>\n";
+ foreach my $img (@images) {
+ $ret .= "<li>";
+ $ret .= htmllink($params{page}, $params{destpage},
+ $viewers{$img});
+ $ret .= "</li>";
+ }
+ return "$ret</ul>\n";
+ }
+
+ sub preprocess_galleryimg {
+ # \[[!galleryimg p1010001.jpg title="" caption="" tags=""]]
+ my $file = $_[0];
+ my %params=@_;
+
+ return "";
+ }
+
+ 1
--- /dev/null
+[[!meta title="Svend Sorensen"]]
+
+* [website](http://www.ciffer.net/~svend/)
+* [blog](http://www.ciffer.net/~svend/blog/)
-[[meta title="Thomas Schwinge"]]
+[[!meta title="Thomas Schwinge"]]
# Thomas Schwinge
<tschwinge@gnu.org>
<http://www.thomas.schwinge.homeip.net/>
-
-With respect to *[[ikiwiki]]* I'm currently working on...
-
-* setting it up for the [GNU Hurd's web pages](http://www.gnu.org/software/hurd/);
-* setting it up as a replacement for the GNU Hurd's previous wiki (TWiki): <http://bddebian.com/~wiki/>;
-
-... and all that while trying to preserve the previous content's history,
-which is stored in a CVS repository for the web pages and a RCS repository
-for the wiki.
-
-Read [About the TWiki to ikiwiki conversion](http://www.bddebian.com/~wiki/about_the_twiki_to_ikiwiki_conversion/).
+I have converted the [GNU Hurd](http://www.gnu.org/software/hurd/)'s previous
+web pages and previous wiki pages to a *[[ikiwiki]]* system; and all that while
+preserving the previous content's history, which was stored in a CVS repository
+for the HTML web pages and a TWiki RCS repository for the wiki; see
+<http://www.gnu.org/software/hurd/colophon.html>.
-[[meta title="Victor Moral"]]
+[[!meta title="Victor Moral"]]
I'm a spanish perl programmer and linux system administrator.
--- /dev/null
+email: weakish@gmail.com
--- /dev/null
+[My blog](http://millenniumdark.blog.ubuntu.org.cn)
+
+> So, you're learning haskell. You know, I want to add support for haskell
+> external plugins to ikiwiki.. :-) --[[Joey]]
--- /dev/null
+[[!meta title="Xavier Maillard"]]
+# Xavier Maillard
+
+I just started using [[ikiwiki]] for my own webspace at http://maillard.mobi/~xma/wiki
+
+I am learning how to effectively use it.
+
+Anyway, [[ikiwiki]] is really *awesome* !
+
+## More about me
+
+I am CLI user living in the linux console. More precisely, I live in an [[GNU_Emacs]] frame all day long. My main computer is an EeePC 901 running Slackware GNU/Linux 12.1. I do not have X installed (too lazy) but when in X, I am running an instance of [[CLFSWM]].
+
+## Contacting me
+
+Various channels to contact me:
+
+- mail: xma@gnu.org
+- jabber: xma01@jabber.fr
+- mobile: +33 621-964-362 (I only anwser to people I know though)
+
+Voila.
+
+## Plans
+
+I am planning to make a presentation of [[ikiwiki]]to my [local LUG](http://lolica.org) for our next montly meeting. Any help would be greatly appreciated.
+
+We are discussing to replace our old unmaintained (and unmaintainable) [SPIP](http://spip.net) website with a wiki. This is why I would like using ikiwiki ;)
--- /dev/null
+How do you edit this wiki (I mean [ikiwiki]) without the web browser ? Is there a way to git clone/pull/push and thus to use our favorite [text editor](http://www.gnu.org/software/emacs) ? --[[xma]]
+
+> You can clone ikiwiki's [[git]] repo. I have not implemented a way to
+> allow users to push doc wiki only changesets anonymously, but you can
+> mails changesets to me. --[[Joey]]
+> > How can I send you the changesets ? (git command) --[[xma]]
+> > > `git-format-patch` --[[Joey]]
+
+> > > > Glad to hear I can mail changesets to you, since I wrote the [[todo/applydiff_plugin]] wishlist entry. --[[intrigeri]]
+
+> It would be nice to have a git recieve hook that
+> checked that a commit contained only changes to .mdwn or other allowed
+> extensions.. if someone writes up a good one, I'd be willing to deploy it
+> for ikiwiki. --[[Joey]]
+
+> > I'll think about it. It may solve some of my offline-being issues. --[[intrigeri]]
+
+>>>> Now developed! --[[Joey]]
cgiurl => 'ikiwiki.cgi',
rcs => "",
- wrappers => [
- {
- # The cgi wrapper.
- cgi => 1,
- # The wrapper must be put in ~/.ikiwiki/wrappers/, since
- # ikiwiki-w3m.cgi only looks in this one location.
- # The wrapper can be given any name as long as it's
- # in that directory.
- wrapper => "$ENV{HOME}/.ikiwiki/wrappers/ikiwiki.cgi",
- wrappermode => "0755",
- },
- ],
-
+ # The wrapper must be put in ~/.ikiwiki/wrappers/, since
+ # ikiwiki-w3m.cgi only looks in this one location.
+ # The wrapper can be given any name as long as it's
+ # in that directory.
+ cgi_wrapper => "$ENV{HOME}/.ikiwiki/wrappers/ikiwiki.cgi",
+ cgi_wrappermode => "0755",
+
add_plugins => [qw{anonok}],
rss => 1,
atom => 1,
* `change.tmpl` - Used to create a page describing a change made to the wiki.
* `passwordmail.tmpl` - Not a html template, this is used to
generate a mail with an url the user can use to reset their password.
-* `rsspage.tmpl` - Used for generating rss feeds for [[blogs|ikiwiki/blog]].
+* `rsspage.tmpl` - Used for generating rss feeds for [[blogs|blog]].
* `rssitem.tmpl` - Used for generating individual items on rss feeds.
* `atompage.tmpl` - Used for generating atom feeds for blogs.
* `atomitem.tmpl` - Used for generating individual items on atom feeds.
* `inlinepage.tmpl` - Used for adding a page inline in a blog
page.
* `archivepage.tmpl` - Used for listing a page in a blog archive page.
+* `microblog.tmpl` - Used for showing a microblogging post inline.
* `blogpost.tmpl` - Used for a form to add a post to a blog (and a rss/atom links)
* `feedlink.tmpl` - Used to add rss/atom links if blogpost.tmpl is not used.
* `aggregatepost.tmpl` - Used by the [[plugins/aggregate]] plugin to create
form to wiki pages.
* `searchquery.tmpl` - This is an omega template, used by the
[[plugins/search]] plugin.
+* `comment.tmpl` - This template is used to display a comment
+ by the [[plugins/comments]] plugin.
+* `editcomment.tmpl` - This template is the comment post form for the
+ [[plugins/comments]] plugin.
+* `commentmoderation.tmpl` - This template is used to produce the comment
+ moderation form.
+* `recentchanges.tmpl` - This template is used for listing a change
+ on the RecentChanges page.
The [[plugins/pagetemplate]] plugin can allow individual pages to use a
different template than `page.tmpl`.
--- /dev/null
+## Place for local templates
+Where does one put any locally modified templates for an individual ikiwiki? --Ivan Z.
+
+> You can put them whereever you like; the `templatedir` controls
+> where ikiwiki looks for them. --[[Joey]]
+
+Thank you for your response! My question arose out of my intention to make
+custom templates for a wiki--specifically suited for the kind of content
+it will have--so, that would mean I would want to distribute them through
+git together with other content of the wiki. So, for this case the
+separation of conceptually ONE thing (the content, the templates, and the
+config option which orders to use these templates) into THREE separate
+files/repos (the main content repo, the repo with templates, and the config
+file) is not convenient: instead of distributing a single repo, I have to
+tell people to take three things if they want to replicate this wiki. How
+would you solve this inconvenience? Perhaps, a default location of the
+templates *inside* the source repo would do?--Ivan Z.
+
+> I would avoid putting the templates in a subdirectory of the ikiwiki srcdir.
+> (I'd also avoid putting the ikiwiki setup file there.)
+> While it's safe to do either in some cases, there are configurations where
+> it's unsafe. For example, a malicious user could use attachment handling to
+> replace those files with their own, bad versions.
+>
+> So, two ideas for where to put the templatedir and ikiwiki setup.
+
+> * The easiest option is to put your wiki content in a subdirectory
+> ("wiki", say) and point `srcdir` at that.
+> then you can have another subdirectory for the wikitemplates,
+> and put the setup file at the top.
+> * Another option if using git would be to have a separate branch,
+> in the same git repository, that holds wikitemplates and the setup file.
+> Then you check out the repository once to make the `srcdir` available,
+> and have a second checkout, of the other branch, to make the other stuff
+> available.
+>
+> Note that with either of these methods, you have to watch out if
+> giving other direct commit access to the repository. They could
+> still edit the setup file and templates, so only trusted users should
+> be given access. (It is, however, perfectly safe to let people edit
+> the wiki via the web, and is even safe to configure
+> [[tips/untrusted_git_push]] to such a repository.) --[[Joey]]
+
+Thanks, that's a nice and simple idea: to have a subdirectory! I'll try it. --Ivan Z.
+
+A [[!taglink wish|wishlist]]: the ikiwiki program could be improved so that it follows the same logic as git in looking for its config: it could ascend directories until it finds an `.ikiwiki/` directory with `.ikiwiki/setup` and then uses that configuration. Now I'm tired to always type `ikiwiki --setup path/to/the/setup --refresh` when working in my working clone of the sources; I'd like to simply type `ikiwiki` instead, and let it find the setup file. The default location to look for templates could also be made to be a sibling of the setup file: `.ikiwiki/templates/`. --Ivan Z.
-These [[todo]] items constitute a wishlist of all kinds of features and
+These [[todo]] tagged 'wishlist' encompass all kinds of features and
improvements people would like to see in ikiwiki. Good patches for any of
these will likely be accepted.
-[[inline pages="todo/* and !todo/done and !link(todo/done) and
+[[!inline pages="todo/* and !todo/done and !link(todo/done) and
link(wishlist) and !link(patch) and !todo/*/*" archive=yes show=0]]
srcdir => "doc",
destdir => "html",
templatedir => "templates",
+ underlaydirbase => "underlays",
underlaydir => "underlays/basewiki",
- wrappers => [],
discussion => 0,
- exclude => qr/\/discussion/,
+ exclude => qr/\/discussion|bugs\/*|todo\/*/,
locale => '',
verbose => 1,
syslog => 0,
userdir => "users",
usedirs => 0,
+ prefix_directives => 1,
add_plugins => [qw{goodstuff version haiku polygen fortune}],
}
--- /dev/null
+#!/usr/bin/perl
+# Parses list of remotes in doc/git.mdwn, configures git to use them
+# all, and fetches updates from them.
+
+my $error=0;
+
+open (IN, "doc/git.mdwn") || die "doc/git.mdwn: $!";
+while (<IN>) {
+ if (/^\*\s+\[?\[?(\w+)(?:\|\w+)?\]?\]?\s+`([^>]+)`/) {
+ # note that the remote name has to be a simple word (\w)
+ # for security/sanity reasons
+ my $remote=$1;
+ my $url=$2;
+
+ # check configured url to deal with it changing
+ my $info=`git remote show -n $remote`;
+ my ($oldurl)=$info=~/URL: (.*)/m;
+ if ($oldurl ne $url) {
+ system("git remote rm $remote 2>/dev/null");
+ $error |= system("git", "remote", "add", "-f", $remote, $url);
+ }
+ else {
+ $error |= system("git", "fetch", $remote);
+ }
+ }
+}
+close IN;
+
+exit $error;
rcs="$1"
srcdir="$2"
repository="$3"
-
+
usage () {
- echo "usage: ikiwiki-makerepo svn|git srcdir repository" >&2
+ echo "usage: ikiwiki-makerepo svn|git|monotone|darcs srcdir repository" >&2
echo " ikiwiki-makerepo bzr|mercurial srcdir" >&2
exit 1
}
fi
if [ "$rcs" != mercurial ] && [ "$rcs" != bzr ]; then
+ if [ -z "$repository" ]; then
+ echo "you need to specify both a srcdir and a repository for $rcs" >&2
+ usage
+ fi
if [ -e "$repository" ]; then
echo "repository $repository already exists, aborting" >&2
exit 1
fi
- repository="$(perl -e 'use Cwd q{abs_path}; $r=shift; $r=~s/\/*$//; print abs_path($r)' $repository)"
+ repository="$(perl -e 'use Cwd; $r=shift; $r=getcwd.q{/}.$r if $r!~m!^/!; print $r' "$repository")"
if [ -z "$repository" ]; then
echo "internal error finding repository abs_path" >&2
exit 1
hg init "$srcdir"
cd "$srcdir"
echo .ikiwiki > .hgignore
- hg add * .hgignore
+ hg add
hg commit -m "initial import"
echo "Directory $srcdir is now set up as a mercurial repository"
;;
bzr init "$srcdir"
cd "$srcdir"
echo .ikiwiki > .bzrignore
- bzr add * .bzrignore
+ bzr add
bzr commit -m "initial import"
echo "Directory $srcdir is now set up as a bzr repository"
;;
+monotone)
+ if [ -e "$srcdir/_MTN" ]; then
+ echo "$srcdir already seems to be a monotone working copy" >&2
+ exit 1
+ fi
+
+ mkdir -p "$(dirname "$repository")"
+ mtn db init -d "$repository"
+
+ cleaned_srcdir=$(basename "$srcdir" | tr -s "[:space:]" "_" | sed 's/_$//g')
+ reverse_hostname=$( (hostname -f 2>/dev/null || hostname) |\
+ tr "." "\n" | ( tac 2>/dev/null || tail -r ) | tr "\n" "." )
+ branch_name="$reverse_hostname$cleaned_srcdir"
+ mtn setup -d "$repository" -b "$branch_name" "$srcdir"
+
+ cd "$srcdir"
+ echo \.ikiwiki$ > .mtn-ignore
+ mtn add -R .
+ # this expects that you already have a working mtn environment
+ # with a default key floating around...
+ mtn ci -m "initial import"
+ echo "Directory $srcdir is now set up as a monotone repository"
+ echo ""
+ echo "Note: If your monotone key has a passphrase, you need to configure"
+ echo "monotone to automatically use it. Otherwise, web commits to ikiwiki"
+ echo "will fail."
+ echo ""
+ echo "You can create a $srcdir/_MTN/monotonerc"
+ echo "containing the passphrase:"
+ echo ""
+ echo "function get_passphrase (branchname)"
+ echo ' return "passphrasehere"'
+ echo "end"
+;;
+darcs)
+ if [ -e "$srcdir/_darcs" ]; then
+ echo "$srcdir already seems to be a darcs repository" >&2
+ exit 1
+ fi
+
+ mkdir -p "$repository"
+ (cd "$repository" && darcs initialize)
+
+ mkdir -p "$srcdir"
+ cd "$srcdir"
+ darcs initialize
+ echo .ikiwiki >> _darcs/prefs/boring
+ darcs record -a -l -q -m "initial import"
+ darcs pull -a -q "$repository"
+ darcs push -a -q "$repository"
+ echo "Directory $srcdir is now a branch of darcs repo $repository"
+
+ # set up master repo's apply hook and tell user to adjust it if desired
+ darcsdefaults="$repository/_darcs/prefs/defaults"
+ echo "Preconfiguring apply hook in $darcsdefaults - adjust as desired!"
+ echo "apply posthook $repository/_darcs/ikiwiki-wrapper" >> "$darcsdefaults"
+ echo "apply run-posthook" >> "$darcsdefaults"
+;;
*)
echo "Unsupported revision control system $rcs" >&2
usage
-#!/usr/bin/perl -i
+#!/usr/bin/perl
use warnings;
use strict;
use IkiWiki;
}
sub prefix_directives {
- $/=undef; # process whole files at once
-
- while (<>) {
- s{$regex}{handle_directive($1, $2, $3, $4)}eg;
- print;
+ loadsetup(shift);
+
+ IkiWiki::loadplugins();
+ IkiWiki::checkconfig();
+ IkiWiki::loadindex();
+
+ if (! %pagesources) {
+ error "ikiwiki has not built this wiki yet, cannot transition";
+ }
+
+ foreach my $page (values %pagesources) {
+ next unless defined pagetype($page) &&
+ -f $config{srcdir}."/".$page;
+ my $content=readfile($config{srcdir}."/".$page);
+ my $oldcontent=$content;
+ $content=~s{$regex}{handle_directive($1, $2, $3, $4)}eg;
+ if ($oldcontent ne $content) {
+ writefile($page, $config{srcdir}, $content);
+ }
}
}
sub indexdb {
- $config{wikistatedir}=shift()."/.ikiwiki";
-
- if (! defined $config{wikistatedir}) {
- usage();
- }
+ setstatedir(shift);
# Note: No lockwiki here because ikiwiki already locks it
# before calling this.
}
sub hashpassword {
- $config{wikistatedir}=shift()."/.ikiwiki";
+ setstatedir(shift);
- if (! defined $config{wikistatedir}) {
- usage();
- }
-
eval q{use IkiWiki::UserInfo};
eval q{use Authen::Passphrase::BlowfishCrypt};
if ($@) {
}
}
+sub aggregateinternal {
+ loadsetup(shift);
+ require IkiWiki::Plugin::aggregate;
+ IkiWiki::checkconfig();
+ IkiWiki::Plugin::aggregate::migrate_to_internal();
+}
+
+sub setupformat {
+ my $setup=shift;
+
+ loadsetup($setup);
+ IkiWiki::checkconfig();
+
+ # unpack old-format wrappers setting into new fields
+ my $cgi_seen=0;
+ my $rcs_seen=0;
+ foreach my $wrapper (@{$config{wrappers}}) {
+ if ($wrapper->{cgi}) {
+ if ($cgi_seen) {
+ die "don't know what to do with second cgi wrapper ".$wrapper->{wrapper}."\n";
+ }
+ $cgi_seen++;
+ print "setting cgi_wrapper to ".$wrapper->{wrapper}."\n";
+ $config{cgi_wrapper}=$wrapper->{wrapper};
+ $config{cgi_wrappermode}=$wrapper->{wrappermode}
+ if exists $wrapper->{wrappermode};
+ }
+ elsif ($config{rcs}) {
+ if ($rcs_seen) {
+ die "don't know what to do with second rcs wrapper ".$wrapper->{wrapper}."\n";
+ }
+ $rcs_seen++;
+ print "setting $config{rcs}_wrapper to ".$wrapper->{wrapper}."\n";
+ $config{$config{rcs}."_wrapper"}=$wrapper->{wrapper};
+ $config{$config{rcs}."_wrappermode"}=$wrapper->{wrappermode}
+ if exists $wrapper->{wrappermode};
+ }
+ else {
+ die "don't know what to do with wrapper ".$wrapper->{wrapper}."\n";
+ }
+ }
+
+ IkiWiki::Setup::dump($setup);
+}
+
+sub moveprefs {
+ my $setup=shift;
+
+ loadsetup($setup);
+ IkiWiki::checkconfig();
+
+ eval q{use IkiWiki::UserInfo};
+ error $@ if $@;
+
+ foreach my $field (qw{allowed_attachments locked_pages}) {
+ my $orig=$config{$field};
+ foreach my $admin (@{$config{adminuser}}) {
+ my $a=IkiWiki::userinfo_get($admin, $field);
+ if (defined $a && length $a &&
+ # might already have been moved
+ (! defined $orig || $a ne $orig)) {
+ if (defined $config{$field} &&
+ length $config{$field}) {
+ $config{$field}=IkiWiki::pagespec_merge($config{$field}, $a);
+ }
+ else {
+ $config{$field}=$a;
+ }
+ }
+ }
+ }
+
+ my %banned=map { $_ => 1 } @{$config{banned_users}}, IkiWiki::get_banned_users();
+ $config{banned_users}=[sort keys %banned];
+
+ IkiWiki::Setup::dump($setup);
+}
+
+sub deduplinks {
+ loadsetup(shift);
+ IkiWiki::loadplugins();
+ IkiWiki::checkconfig();
+ IkiWiki::loadindex();
+ foreach my $page (keys %links) {
+ my %l;
+ $l{$_}=1 foreach @{$links{$page}};
+ $links{$page}=[keys %l]
+ }
+ IkiWiki::saveindex();
+}
+
+sub setstatedir {
+ my $dirorsetup=shift;
+
+ if (! defined $dirorsetup) {
+ usage();
+ }
+
+ if (-d $dirorsetup) {
+ $config{wikistatedir}=$dirorsetup."/.ikiwiki";
+ }
+ elsif (-f $dirorsetup) {
+ loadsetup($dirorsetup);
+ }
+ else {
+ error("ikiwiki-transition: $dirorsetup does not exist");
+ }
+
+ if (! -d $config{wikistatedir}) {
+ error("ikiwiki-transition: $config{wikistatedir} does not exist");
+ }
+}
+
+sub loadsetup {
+ my $setup=shift;
+ if (! defined $setup) {
+ usage();
+ }
+
+ require IkiWiki::Setup;
+
+ %config = IkiWiki::defaultconfig();
+ IkiWiki::Setup::load($setup);
+}
+
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 "\tprefix_directives setupfile ...\n";
+ print STDERR "\taggregateinternal setupfile\n";
+ print STDERR "\tsetupformat setupfile\n";
+ print STDERR "\tmoveprefs setupfile\n";
+ print STDERR "\thashpassword setupfile|srcdir\n";
+ print STDERR "\tindexdb setupfile|srcdir\n";
+ print STDERR "\tdeduplinks setupfile\n";
exit 1;
}
if ($mode eq 'prefix_directives') {
prefix_directives(@ARGV);
}
-if ($mode eq 'hashpassword') {
+elsif ($mode eq 'hashpassword') {
hashpassword(@ARGV);
}
elsif ($mode eq 'indexdb') {
indexdb(@ARGV);
}
+elsif ($mode eq 'aggregateinternal') {
+ aggregateinternal(@ARGV);
+}
+elsif ($mode eq 'setupformat') {
+ setupformat(@ARGV);
+}
+elsif ($mode eq 'moveprefs') {
+ moveprefs(@ARGV);
+}
+elsif ($mode eq 'deduplinks') {
+ deduplinks(@ARGV);
+}
else {
usage();
}
$pagemtime{$page}=$items{mtime}[0];
$oldlinks{$page}=[@{$items{link}}];
$links{$page}=[@{$items{link}}];
- $depends{$page}=$items{depends}[0] if exists $items{depends};
+ $depends{$page}={ $items{depends}[0] => 1 } if exists $items{depends};
$destsources{$_}=$page foreach @{$items{dest}};
$renderedfiles{$page}=[@{$items{dest}}];
$pagecase{lc $page}=$page;
return close($in);
}
+
+# Used to be in IkiWiki/UserInfo, but only used here now.
+sub get_banned_users () {
+ my @ret;
+ my $userinfo=userinfo_retrieve();
+ foreach my $user (keys %{$userinfo}) {
+ push @ret, $user if $userinfo->{$user}->{banned};
+ }
+ return @ret;
+}
+
+# Used to be in IkiWiki, but only used here (to migrate admin prefs into the
+# setup file) now.
+sub pagespec_merge ($$) {
+ my $a=shift;
+ my $b=shift;
+
+ return $a if $a eq $b;
+ return "($a) or ($b)";
+}
+
+1
use strict;
use English;
+my $remove=(@ARGV && $ARGV[0] eq '-r');
+
my $username=getpwuid($REAL_USER_ID);
if (! defined $username || ! length $username) {
die "unable to determine user name for UID $REAL_USER_ID\n";
die "$wikilist does not exist\n";
}
-my $removed=0;
+my $changed=0;
+my $seen=0;
my @lines;
open (my $list, "<$wikilist") || die "read $wikilist: $!";
while (<$list>) {
if (/^\s*([^\s]+)\s*$/) {
my $user=$1;
if ($user eq $username) {
- $removed=1;
+ if (! $remove) {
+ $seen=1;
+ push @lines, $_;
+ }
}
else {
push @lines, $_;
push @lines, $_;
}
}
-close $list || die "error reading $list: $!";
-open ($list, ">$wikilist") || die "write $wikilist: $!";
-foreach (@lines) {
- print $list "$_\n";
+if (! $seen && ! $remove) {
+ push @lines, $username;
+ $changed=1;
}
-if ($removed) {
- print "removed user $username from $wikilist\n";
+if ($changed) {
+ close $list || die "ikiwiki-update-wikilist: error reading $list: $!\n";
+ open ($list, ">$wikilist") || die "ikiwiki-update-wikilist: cannot write to $wikilist\n";
+ foreach (@lines) {
+ print $list "$_\n";
+ }
+ if ($remove) {
+ print "ikiwiki-update-wikilist: removed user $username from $wikilist\n";
+ }
+ else {
+ print "ikiwiki-update-wikilist: added user $username to $wikilist\n";
+ }
+ close $list || die "ikiwiki-update-wikilist: error writing $wikilist: $!\n";
}
else {
- print $list "$username\n";
- print "added user $username to $wikilist\n";
+ print "ikiwiki-update-wikilist: no changes need to be made\n";
}
-close $list || die "error writing $list: $!";
-#!/usr/bin/perl -T
+#!/usr/bin/perl
$ENV{PATH}="/usr/local/bin:/usr/bin:/bin";
delete @ENV{qw{IFS CDPATH ENV BASH_ENV}};
use lib '.'; # For use in nonstandard directory, munged by Makefile.
use IkiWiki;
-sub usage () { #{{{
- die gettext("usage: ikiwiki [options] source dest"), "\n";
-} #}}}
+sub usage () {
+ die gettext("usage: ikiwiki [options] source dest"), "\n",
+ gettext(" ikiwiki --setup configfile"), "\n";
+}
-sub getconfig () { #{{{
+sub getconfig () {
if (! exists $ENV{WRAPPED_OPTIONS}) {
%config=defaultconfig();
eval q{use Getopt::Long};
Getopt::Long::Configure('pass_through');
GetOptions(
- "setup|s=s" => \$config{setup},
+ "setup|s=s" => sub {
+ require IkiWiki::Setup;
+ my $verbose=$config{verbose};
+ my $syslog=$config{syslog};
+ IkiWiki::Setup::load($_[1]);
+ $config{setupverbose}=$config{verbose};
+ $config{setupsyslog}=$config{syslog};
+ $config{verbose}=$verbose || $config{setupverbose};
+ $config{syslog}=$syslog;
+ $config{setup}=1;
+ },
+ "dumpsetup|s=s" => \$config{dumpsetup},
"wikiname=s" => \$config{wikiname},
"verbose|v!" => \$config{verbose},
"syslog!" => \$config{syslog},
"refresh!" => \$config{refresh},
"post-commit" => \$config{post_commit},
"render=s" => \$config{render},
- "wrappers!" => \$config{wrappers},
+ "wrappers!" => \$config{genwrappers},
+ "wrappergroup=s" => \$config{wrappergroup},
"usedirs!" => \$config{usedirs},
"prefix-directives!" => \$config{prefix_directives},
"getctime" => \$config{getctime},
"adminemail=s" => \$config{adminemail},
"timeformat=s" => \$config{timeformat},
"sslcookie!" => \$config{sslcookie},
- "httpauth!" => \$config{httpauth},
"userdir=s" => \$config{userdir},
"htmlext=s" => \$config{htmlext},
"libdir=s" => \$config{libdir},
$config{wrappermode}=possibly_foolish_untaint($_[1])
},
"plugin=s@" => sub {
- push @{$config{plugin}}, $_[1];
+ push @{$config{add_plugins}}, $_[1];
},
"disable-plugin=s@" => sub {
push @{$config{disable_plugins}}, $_[1];
},
- "pingurl=s" => sub {
- push @{$config{pingurl}}, $_[1];
- },
"set=s" => sub {
my ($var, $val)=split('=', $_[1], 2);
if (! defined $var || ! defined $val) {
print "ikiwiki version $IkiWiki::version\n";
exit;
},
+ "help|h" => sub { $SIG{__WARN__}=sub {}; die },
) || usage();
- if (! $config{setup} && ! $config{render}) {
+ if (! $config{setup}) {
loadplugins();
- usage() unless @ARGV == 2;
- $config{srcdir} = possibly_foolish_untaint(shift @ARGV);
- $config{destdir} = possibly_foolish_untaint(shift @ARGV);
- checkconfig();
+ if (@ARGV == 2) {
+ $config{srcdir} = possibly_foolish_untaint(shift @ARGV);
+ $config{destdir} = possibly_foolish_untaint(shift @ARGV);
+ checkconfig();
+ }
+ else {
+ usage() unless $config{dumpsetup};
+ }
}
}
else {
if ($@) {
error("WRAPPED_OPTIONS: $@");
}
+ delete $ENV{WRAPPED_OPTIONS};
+
loadplugins();
checkconfig();
}
-} #}}}
+}
-sub main () { #{{{
+sub main () {
getconfig();
if ($config{setup}) {
+ delete $config{setup};
+ loadplugins();
+ checkconfig();
+
+ if (@{$config{wrappers}} &&
+ ! $config{render} && ! $config{dumpsetup} &&
+ ((! $config{refresh} && ! $config{post_commit})
+ || $config{genwrappers})) {
+ debug(gettext("generating wrappers.."));
+ require IkiWiki::Wrapper;
+ my %origconfig=(%config);
+ foreach my $wrapper (@{$config{wrappers}}) {
+ %config=(%origconfig, %{$wrapper});
+ $config{verbose}=$config{setupverbose}
+ if exists $config{setupverbose};
+ $config{syslog}=$config{setupsyslog}
+ if exists $config{setupsyslog};
+ delete @config{qw(setupsyslog setupverbose wrappers genwrappers rebuild)};
+ checkconfig();
+ if (! $config{cgi} && ! $config{post_commit} &&
+ ! $config{test_receive}) {
+ $config{post_commit}=1;
+ }
+ gen_wrapper();
+ }
+ %config=(%origconfig);
+ }
+
+ # setup implies a wiki rebuild by default
+ if (! $config{refresh} && ! $config{render} &&
+ ! $config{post_commit}) {
+ $config{rebuild}=1;
+ }
+ }
+
+ if ($config{dumpsetup}) {
+ $config{srcdir}="" if ! defined $config{srcdir};
+ $config{destdir}="" if ! defined $config{destdir};
+ $config{syslog}=1 if $config{setupsyslog};
require IkiWiki::Setup;
- setup();
+ IkiWiki::Setup::dump($config{dumpsetup});
}
elsif ($config{wrapper}) {
lockwiki();
}
elsif ($config{cgi}) {
require IkiWiki::CGI;
- cgi();
+ eval {cgi()};
+ if ($@) {
+ cgierror($@);
+ }
}
elsif ($config{render}) {
require IkiWiki::Render;
elsif ($config{post_commit} && ! commit_hook_enabled()) {
# do nothing
}
+ elsif ($config{test_receive}) {
+ require IkiWiki::Receive;
+ IkiWiki::Receive::test();
+ }
else {
+ if ($config{rebuild}) {
+ debug(gettext("rebuilding wiki.."));
+ }
+ else {
+ debug(gettext("refreshing wiki.."));
+ }
lockwiki();
loadindex();
require IkiWiki::Render;
rcs_update();
refresh();
saveindex();
+ debug(gettext("done"));
}
-} #}}}
+}
main;
# stage of ikiwiki.
rpc_call("hook", type => "preprocess", id => "externaldemo", call => "preprocess");
- # Here's an example of how to inject an arbitrary function into
- # ikiwiki. Ikiwiki will be able to call bob() just like any other
- # function. Note use of automatic memoization.
- rpc_call("inject", name => "IkiWiki::bob", call => "bob",
- memoize => 1);
-
# Here's an exmaple of how to access values in %IkiWiki::config.
print STDERR "url is set to: ".
rpc_call("getvar", "config", "url")."\n";
+ # Here's an example of how to inject an arbitrary function into
+ # ikiwiki. Note use of automatic memoization.
+ rpc_call("inject", name => "IkiWiki::bob",
+ call => "formattime", memoize => 1);
+
print STDERR "externaldemo plugin successfully imported\n";
}
})
return '\n'.join(parts['html_body'].splitlines()[1:-1])
+def getsetup(proxy, *kwargs):
+ return 'plugin', { 'safe' : 1, 'rebuild' : 1 }
+
import sys
def debug(s):
sys.stderr.write(__name__ + ':DEBUG:%s\n' % s)
sys.stderr.flush()
proxy = IkiWikiProcedureProxy(__name__, debug_fn=None)
+proxy.hook('getsetup', getsetup)
proxy.hook('htmlize', rst2html)
proxy.run()
}
if (/INSTALLDIR_AUTOREPLACE/) {
- $_=qq{my \$installdir="$prefix";};
+ $_=qq{our \$installdir="$prefix";};
}
elsif (/VERSION_AUTOREPLACE/) {
$_=qq{our \$version="$ver";};
}
elsif (/^use lib/) {
# The idea here is to figure out if the libdir the Makefile.PL
- # was configure to use is in perl's normal search path.
+ # was configured to use is in perl's normal search path.
# If not, hard code it into ikiwiki.
if ((grep { $_ eq $libdir } @INC) &&
(! exists $ENV{PERL5LIB} || ! length $ENV{PERL5LIB} ||
$_="use lib '$libdir';\n";
}
}
-elsif ($. == 1 && ($ENV{NOTAINT} || ! exists $ENV{NOTAINT}) && m{^(#!.*perl.*?) -T$}) {
- $_=qq{$1\n};
+elsif ($. == 1 && ($ENV{NOTAINT}=0) && m{^(#!.*perl.*?)$}) {
+ $_=qq{$1 -T\n};
}
elsif (/^\$ENV{PATH}="(.*)";/) {
$_="\$ENV{PATH}=\"$1:$prefix/bin\";\n";
# List here all source files with translatable strings.
POTFILES=$(sort $(shell find ../IkiWiki -type f -name \*.pm)) \
- ../ikiwiki.in ../IkiWiki.pm
+ ../ikiwiki.in ../IkiWiki.pm ../auto.setup
POFILES=$(wildcard *.po)
MOFILES=$(POFILES:.po=.mo)
-all: ikiwiki.pot mo
+# Translated underlays can only be generated if po4a is available.
+TRANSLATED_UNDERLAYS=$(shell if perl -e 'use Locale::Po4a::Common' 2>/dev/null; then echo ../underlays/locale; fi)
+
+all: ikiwiki.pot mo $(TRANSLATED_UNDERLAYS)
mo: $(MOFILES)
install: all
+ # Normal mo files for program translation.
for file in $(MOFILES); do \
lang=`echo $$file | sed 's/\.mo//'`; \
install -d $(DESTDIR)$(PREFIX)/share/locale/$$lang/LC_MESSAGES/; \
install -m 0644 $$file $(DESTDIR)$(PREFIX)/share/locale/$$lang/LC_MESSAGES/ikiwiki.mo; \
done
+
+ # Underlay translation via po files that go in special per-language
+ # underlays.
+ for file in `cd underlays && find . -type f -name \*.po`; do \
+ lang=`echo $$file | sed -e 's/.po$$//' -e 's/.*\\.//'`; \
+ dir=`dirname "$(DESTDIR)$(PREFIX)/share/ikiwiki/po/$$lang/$$file"`; \
+ install -d $$dir; \
+ install -m 0644 underlays/$$file $$dir; \
+ done
ikiwiki.pot: $(POTFILES)
@if perl -e '($$ver)=`xgettext -V | head -n 1`=~/.*\s+([0-9]+\.[0-9]+)/; die "gettext $$ver too old, not updating the pot file\n" if $$ver < 0.16'; then \
echo "Rebuilding the pot file"; \
- xgettext $(POTFILES) -o ikiwiki.pot -Lperl --add-comments=translators; \
+ xgettext --from-code=UTF-8 $(POTFILES) -o ikiwiki.pot -Lperl --add-comments=translators; \
fi
clean:
- rm -f $(MOFILES) messages messages.mo
+ rm -f $(MOFILES) messages messages.mo *_stamp
+ rm -rf html underlays/.ikiwiki $(TRANSLATED_UNDERLAYS)
+ find underlays -name \*.mdwn -or -name \*.pot | xargs rm -f
%.mo: %.po
msgfmt -o $@ $<
-%.po:
+%.po: ikiwiki.pot
@echo -n "Merging ikiwiki.pot and $@"
@msgmerge $@ ikiwiki.pot -o $@.new 2>&1
# Typically all that changes was a date or line number. I'd prefer not to
printf "$$lang: "; \
msgfmt -o /dev/null -c -v --statistics $$lang.po;\
done
+
+underlays_copy_stamp:
+ # copy all the files we want to translate into a srcdir
+ for file in `cd ..; find underlays -follow -name \*.mdwn`; do \
+ install -d $$(dirname $$file); \
+ cp -aL ../$$file $$file 2>/dev/null || \
+ install -m 644 ../$$file $$file; \
+ done
+ install -d underlays/directives/ikiwiki/directive
+ for file in `cd ..; find doc/ikiwiki/directive/ -maxdepth 1 -type f`; do \
+ cp -a ../$$file underlays/directives/ikiwiki/directive || \
+ install -m 644 ../$$file underlays/directives/ikiwiki/directive; \
+ done
+ install -d underlays/empty
+ touch $@
+
+underlays: ../ikiwiki.out underlays_copy_stamp
+ ../ikiwiki.out -libdir .. -setup underlay.setup -refresh
+
+../ikiwiki.out: ../Makefile
+ make -C .. ikiwiki.out
+
+../Makefile: ../Makefile.PL
+ cd .. && ./Makefile.PL
+
+$(TRANSLATED_UNDERLAYS): po2wiki_stamp
+po2wiki_stamp: po2wiki underlays_copy_stamp
+ PERL5LIB=.. ./po2wiki underlay.setup
+ touch $@
+
+.PHONY: underlays
msgstr ""
"Project-Id-Version: ikiwiki-bg\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
"PO-Revision-Date: 2007-01-12 01:19+0200\n"
"Last-Translator: Damyan Ivanov <dam@modsodtsys.com>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Първо трябва да влезете."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr ""
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
#, fuzzy
msgid "Preferences"
msgstr "Предпочитанията са запазени."
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr ""
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Предпочитанията са запазени."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr ""
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "дискусия"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Достъпът ви е забранен."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "създаване на %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Грешка"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "промяна на %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr ""
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "Достъпът ви е забранен."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, fuzzy, perl-format
msgid "missing %s parameter"
msgstr "липсващ параметър „id” на шаблона"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "нов източник"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "съобщения"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "ново"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "премахване на „%s” (на %s дни)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "премахване на „%s”"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "е обработен нормално от %s"
+msgid "last checked %s"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "проверка на източника „%s”"
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "не е намерен източник на адрес „%s”"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
#, fuzzy
msgid "feed not found"
msgstr "шаблонът „%s” не е намерен"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "данните от източника предизвикаха грешка в модула XML::Feed!"
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "създаване на нова страницa „%s”"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "готово"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Грешка при изпращане на поща"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Грешка при изпращане на поща"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "грешка при запис на файла „%s”: %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr ""
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "Няма „счупени” връзки!"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, fuzzy, perl-format
+msgid "commenting on %s"
+msgstr "създаване на %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, fuzzy, perl-format
+msgid "removing old preview %s"
+msgstr "премахване на старата страница „%s”"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "създаване на %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "промяна на %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
#, fuzzy
msgid "template not specified"
msgstr "шаблонът „%s” не е намерен"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
#, fuzzy
msgid "match not specified"
msgstr "не е указан файл на обвивката"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
#, fuzzy
msgid "failed to process"
msgstr "грешка при обработване на шаблона"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "грешшка в приставката „fortune”"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+#, fuzzy
+msgid "missing page"
+msgstr "липсващ параметър „id” на шаблона"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
#, fuzzy
-msgid "failed to find url in html"
-msgstr "приставката „googlecalendar” не намери URL в HTML-кода"
+msgid "not a page"
+msgstr "грешка при четене на „%s”: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, perl-format
+msgid "%s is an attachment, not a page."
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "При използване на приеставката „search” е необходимо е да се укаже %s"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
#, fuzzy
msgid "failed to run graphviz"
msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+#, fuzzy
+msgid "Image::Magick is not installed"
+msgstr "не е инсталиран polygen"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, fuzzy, perl-format
msgid "failed to read %s: %s"
msgstr "грешка при запис на файла „%s”: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, fuzzy, perl-format
msgid "failed to resize: %s"
msgstr "грешка при запис на файла „%s”: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, fuzzy, perl-format
msgid "failed to determine size of image %s"
msgstr "грешка при запис на файла „%s”: %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
"Когато се използва „--rss” или „--atom” трябва да се укаже и "
"местоположението на уикито посредством параметъра „--url”"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+#, fuzzy
+msgid "page editing not allowed"
+msgstr "шаблонът „%s” не е намерен"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+#, fuzzy
+msgid "missing pages parameter"
+msgstr "липсващ параметър „id” на шаблона"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "непознат вид сортиране „%s”"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Дискусия"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "модулът „RPC::XML::Client” не е намерен; източникът не е проверен"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
#, fuzzy
msgid "failed to run dot"
msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
-#: ../IkiWiki/Plugin/lockedit.pm:29
-#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, fuzzy, perl-format
+msgid "%s is locked and cannot be edited"
msgstr ""
"Страницата „%s” е заключена от потребителя „%s” и не може да бъде променяна"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"грешка при зареждането на perl-модула „Markdown.pm” (%s) или „/usr/bin/"
"markdown” (%s)"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
#, fuzzy
msgid "stylesheet not found"
msgstr "шаблонът „%s” не е намерен"
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
#, fuzzy
msgid "redir page not found"
msgstr "шаблонът „%s” не е намерен"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
#, fuzzy
msgid "redir cycle is not allowed"
msgstr "шаблонът „%s” не е намерен"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Огледала"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Огледало"
msgid "more"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "функцията „getctime” не е реализирана"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Получаване на OpenID номер"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "Всички страници имат връзки от други страници."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Акаунтът е създаден. Можете да влезете."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Грешка при създаване на акаунта."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Грешка при изпращане на поща"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Паролата ви е изпратена по пощата."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, fuzzy, perl-format
+msgid "Will ping %s"
+msgstr "промяна на %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+#, fuzzy
+msgid "LWP not found, not pinging"
+msgstr "модулът „RPC::XML::Client” не е намерен; източникът не е проверен"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "промяна на %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "крешка при компилиране на файла %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "крешка при компилиране на файла %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "крешка при компилиране на файла %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "грешка при запис на файла „%s”: %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "грешка при запис на файла „%s”: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "грешка при запис на файла „%s”: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "гласуване"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Общо гласове:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "не е инсталиран polygen"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "грешка при изпълнението на poligen"
+#: ../IkiWiki/Plugin/polygen.pm:60
+#, fuzzy
+msgid "command failed"
+msgstr "грешшка в приставката „fortune”"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr ""
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr ""
msgid "%A night"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:74
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, fuzzy, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr ""
+"Страницата „%s” е заключена от потребителя „%s” и не може да бъде променяна"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
#, fuzzy
-msgid "missing page"
-msgstr "липÑ\81ваÑ\89 паÑ\80амеÑ\82Ñ\8aÑ\80 â\80\9eidâ\80\9d на Ñ\88аблона"
+msgid "no change to the file name was specified"
+msgstr "не е Ñ\83казан Ñ\84айл на обвивкаÑ\82а"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "The page %s does not exist."
+msgid "illegal name"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:73
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "При използване на приеставката „search” е необходимо е да се укаже %s"
+msgid "%s already exists"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "изчистване на индекса за търсене на hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "обновяване на индекса за търсене на hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:122
+#, fuzzy, perl-format
+msgid "rename %s"
+msgstr "обновяване на страницата „%s”"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, fuzzy, perl-format
+msgid "update for rename of %s to %s"
+msgstr "обновяване на страниците от уики „%s”: %s от потребител „%s”"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
#, fuzzy
msgid "missing name or url parameter"
msgstr "препратката няма указани параметрите „name” или „url”"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, fuzzy, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "препратката „%s” сочи към „%s”"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
#, fuzzy
msgid "failed to parse any smileys"
msgstr "няма разпознати усмивки; изключване на приставката „smiley”"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
#, fuzzy
msgid "parse error"
msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:95
+#: ../IkiWiki/Plugin/sparkline.pm:104
#, fuzzy
-msgid "bad height value"
+msgid "invalid height value"
msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
#, fuzzy
msgid "missing width parameter"
msgstr "липсващ параметър „id” на шаблона"
-#: ../IkiWiki/Plugin/sparkline.pm:106
+#: ../IkiWiki/Plugin/sparkline.pm:115
#, fuzzy
-msgid "bad width value"
+msgid "invalid width value"
msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
#, fuzzy
msgid "failed to run php"
msgstr "приставката „linkmap”: грешка при изпълнение на „dot”"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, fuzzy, perl-format
msgid "parse fail at line %d: %s"
msgstr "грешка при запис на файла „%s”: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
#, fuzzy
msgid "missing id parameter"
msgstr "липсващ параметър „id” на шаблона"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "шаблонът „%s” не е намерен"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
#, fuzzy
msgid "failed to process:"
msgstr "грешка при обработване на шаблона"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
#, fuzzy
msgid "failed to generate image from code"
msgstr "грешка при запис на файла „%s”: %s"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "функцията „getctime” не е реализирана"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Receive.pm:85
+#, fuzzy, perl-format
+msgid "bad file name %s"
+msgstr "пропускане на невалидното име на файл „%s”"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "пропускане на невалидното име на файл „%s”"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "премахване на старата страница „%s”"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "сканиране на „%s”"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "обновяване на страницата „%s”"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "обновяване на страницата „%s”, съдържаща препратки към „%s”"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "обновяване на страницата „%s”, зависеща от „%s”"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr "обновяване на „%s” и осъвременяване на обратните връзки"
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "премахване на „%s” понеже не се генерира от „%s”"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: неуспех при обновяване на страницата „%s”"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "грешка при четене на „%s”: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "генериране на обвивки..."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "обновяване на уики..."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "осъвременяване на уики..."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "готово"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "не е указан файл на обвивката"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "грешка при запис на файла „%s”: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "крешка при компилиране на файла %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "успешно генериране на %s"
msgid "usage: ikiwiki [options] source dest"
msgstr "формат: ikiwiki [опции] източник местоназначение"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "генериране на обвивки..."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "обновяване на уики..."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "осъвременяване на уики..."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Дискусия"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
"При използване на пареметъра „--cgi” е необходимо да се укаже и "
"местоположението на уикито чрез параметъра „--url”"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "Грешка"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:569
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1243
+#, fuzzy, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr "открита е циклична завидимост при %s на „%s” на дълбочина %i"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
+#, fuzzy, perl-format
+msgid "cannot match pages: %s"
+msgstr "грешка при четене на „%s”: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr ""
+
+#~ msgid "discussion"
+#~ msgstr "дискусия"
+
+#~ msgid "rendering %s"
+#~ msgstr "обновяване на страницата „%s”"
+
+#, fuzzy
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr ""
+#~ "При използване на приеставката „search” е необходимо е да се укаже %s"
+
+#, fuzzy
+#~ msgid "failed to find url in html"
+#~ msgstr "приставката „googlecalendar” не намери URL в HTML-кода"
+
+#~ msgid "processed ok at %s"
+#~ msgstr "е обработен нормално от %s"
+
+#~ msgid "Your password has been emailed to you."
+#~ msgstr "Паролата ви е изпратена по пощата."
+
+#~ msgid "polygen failed"
+#~ msgstr "грешка при изпълнението на poligen"
+
+#~ msgid "cleaning hyperestraier search index"
+#~ msgstr "изчистване на индекса за търсене на hyperestraier"
+
+#~ msgid "updating hyperestraier search index"
+#~ msgstr "обновяване на индекса за търсене на hyperestraier"
+
#, fuzzy
#~ msgid ""
#~ "REV is not set, not running from mtn post-commit hook, cannot send "
#~ "изпълнява като „svn post-commit hook”. Няма да бъдат разпратени "
#~ "известявания"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "обновяване на страниците от уики „%s”: %s от потребител „%s”"
-
#, fuzzy
#~ msgid "%s not found"
#~ msgstr "шаблонът „%s” не е намерен"
msgstr ""
"Project-Id-Version: ikiwiki\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
"PO-Revision-Date: 2007-05-09 21:21+0200\n"
"Last-Translator: Miroslav Kure <kurem@debian.cz>\n"
"Language-Team: Czech <debian-l10n-czech@lists.debian.org>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Nejprve se musíte přihlásit."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr "přihlášení selhalo; možná si musíte povolit cookies?"
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr "Přihlášení"
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
msgid "Preferences"
msgstr "Předvolby"
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr "Správce"
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Nastavení uloženo."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "%s není editovatelná stránka"
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "diskuse"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Jste vyhoštěni."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "vytvářím %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Chyba"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "upravuji %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr ""
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "Jste vyhoštěni."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr "chybí parametr %s"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "nový zdroj"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "příspěvky"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "nový"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "expiruji %s (stará %s dnů)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "expiruji %s"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "zpracováno ok %s"
+msgid "last checked %s"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "kontroluji zdroj %s ..."
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "nemohu najít zdroj na %s"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
msgstr "zdroj nebyl nalezen"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr "(neplatné UTF-8 bylo ze zdroje odstraněno)"
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "zdroj shodil XML::Feed!"
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "vytvářím novou stránku %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "hotovo"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Nepodařilo se odeslat email."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Nepodařilo se odeslat email."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "nelze změnit velikost: %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr ""
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "Žádné porušené odkazy!"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, fuzzy, perl-format
+msgid "commenting on %s"
+msgstr "vytvářím %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr "parametr %s je vyžadován"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, fuzzy, perl-format
+msgid "removing old preview %s"
+msgstr "odstraňuji starou stránku %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "%s není editovatelná stránka"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "vytvářím %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "upravuji %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
#, fuzzy
msgid "template not specified"
msgstr "šablona %s nebyla nalezena"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
#, fuzzy
msgid "match not specified"
msgstr "jméno souboru s obalem nebylo zadáno"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
#, fuzzy
msgid "failed to process"
msgstr "nepodařilo se zpracovat:"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "fortune selhal"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
-msgstr "v html se nepodařilo nalézt url"
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+#, fuzzy
+msgid "missing page"
+msgstr "chybí hodnoty"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+#, fuzzy
+msgid "not a page"
+msgstr "nemohu číst %s: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, fuzzy, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "%s není editovatelná stránka"
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Při používání vyhledávacího modulu musíte zadat %s"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
msgstr "nepodařilo se spustit graphviz"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "program není platným programem graphviz"
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+#, fuzzy
+msgid "Image::Magick is not installed"
+msgstr "polygen není nainstalován"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
-msgstr "chybná velikost \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr ""
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr "nelze číst %s: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
msgstr "nelze změnit velikost: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, fuzzy, perl-format
msgid "failed to determine size of image %s"
msgstr "nelze změnit velikost: %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr "Při používání --rss nebo --atom musíte pomocí --url zadat url k wiki"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+#, fuzzy
+msgid "page editing not allowed"
+msgstr "zdroj nebyl nalezen"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+#, fuzzy
+msgid "missing pages parameter"
+msgstr "chybí parametr %s"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "neznámý typ řazení %s"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr "Přidat nový příspěvek nazvaný:"
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr "neexistující šablona %s"
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Diskuse"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "RPC::XML::Client nebyl nalezen, nepinkám"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr "nepodařilo se spustit dot"
-#: ../IkiWiki/Plugin/lockedit.pm:29
-#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, fuzzy, perl-format
+msgid "%s is locked and cannot be edited"
msgstr "Stránka %s je zamknutá uživatelem %s a nelze ji měnit"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"selhalo nahrání perlového modulu Markdown.pm (%s) nebo /usr/bin/markdown (%s)"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr "styl nebyl nalezen"
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
#, fuzzy
msgid "redir page not found"
msgstr "zdroj nebyl nalezen"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
#, fuzzy
msgid "redir cycle is not allowed"
msgstr "zdroj nebyl nalezen"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Zrcadla"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Zrcadlo"
msgid "more"
msgstr "více"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime není implementováno"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr "Přihlásit pomocí"
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Získat OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "Na každou stránku vede odkaz z jiné stránky."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Vytvoření účtu bylo úspěšné. Nyní se můžete přihlásit."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Chyba při vytváření účtu."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Nepodařilo se odeslat email."
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Vaše heslo vám bylo zasláno."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, fuzzy, perl-format
+msgid "Will ping %s"
+msgstr "upravuji %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+#, fuzzy
+msgid "LWP not found, not pinging"
+msgstr "RPC::XML::Client nebyl nalezen, nepinkám"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, fuzzy, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s není editovatelná stránka"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "upravuji %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "nelze zkompilovat %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "nelze zkompilovat %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "nelze zkompilovat %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "nelze změnit velikost: %s"
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "nelze zapsat %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "nepodařilo se spustit dot"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "nelze číst %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "hlasovat"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Celkem hlasů:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "polygen není nainstalován"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "polygen selhal"
+#: ../IkiWiki/Plugin/polygen.pm:60
+#, fuzzy
+msgid "command failed"
+msgstr "fortune selhal"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "chybí vzorec"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "neznámý vzorec"
msgid "%A night"
msgstr "%A v noci"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "%A během odpoledního čaje"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "o půlnoci"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "%A o poledni"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, fuzzy, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "Stránka %s je zamknutá uživatelem %s a nelze ji měnit"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, fuzzy, perl-format
+msgid "%s is not a file"
+msgstr "%s není editovatelná stránka"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
#, fuzzy
-msgid "missing page"
-msgstr "chybí hodnoty"
+msgid "no change to the file name was specified"
+msgstr "jméno souboru s obalem nebylo zadáno"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "The page %s does not exist."
+msgid "illegal name"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:73
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Při používání vyhledávacího modulu musíte zadat %s"
+msgid "%s already exists"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, fuzzy, perl-format
+msgid "rename %s"
+msgstr "zpracovávám %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "čistím vyhledávací index hyperestraieru"
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, fuzzy, perl-format
+msgid "update for rename of %s to %s"
+msgstr "aktualizace %s (%s) uživatelem %s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "aktualizuji vyhledávací index hyperestraieru"
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr "chybí parametr jméno nebo url"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "zkratka %s odkazuje na <i>%s</i>"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
msgstr "nepodařilo se rozpoznat žádné smajlíky"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
msgstr "chyba rozpoznávání"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+#, fuzzy
+msgid "invalid featurepoint diameter"
msgstr "chybný průměr zvýrazněného bodu (featurepoint)"
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+#, fuzzy
+msgid "invalid featurepoint location"
msgstr "chybné umístění zvýrazněného bodu (featurepoint)"
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "chybí hodnoty"
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+#, fuzzy
+msgid "invalid height value"
msgstr "chybná výška"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
msgstr "chybí parametr šířka (width)"
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+#, fuzzy
+msgid "invalid width value"
msgstr "chybná šířka"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr "nepodařilo se spustit php"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "nemohu najít soubor"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "neznámý formát dat"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr "prázdná data"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "Stáhnout zdrojová data"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
msgstr "zpracovávání selhalo na řádku %d: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
msgstr "chybí parametr id"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "šablona %s nebyla nalezena"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
msgstr "nepodařilo se zpracovat:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
#, fuzzy
msgid "missing tex code"
msgstr "chybí hodnoty"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
#, fuzzy
msgid "failed to generate image from code"
msgstr "nelze změnit velikost: %s"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "getctime není implementováno"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Plugin/websetup.pm:256
+#, fuzzy
+msgid "main"
+msgstr "Správce"
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:85
+#, fuzzy, perl-format
+msgid "bad file name %s"
+msgstr "přeskakuji chybné jméno souboru %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "přeskakuji chybné jméno souboru %s"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "odstraňuji starou stránku %s"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "prohledávám %s"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "zpracovávám %s"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "zpracovávám %s, která odkazuje na %s"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "zpracovávám %s, která závisí na %s"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr "zpracovávám %s, aby se aktualizovaly zpětné odkazy"
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "odstraňuji %s, již není zpracovávána %s"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: nelze zpracovat %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "nemohu číst %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "generuji obaly..."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "znovu vytvářím wiki..."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "obnovuji wiki..."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "hotovo"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "jméno souboru s obalem nebylo zadáno"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "nelze zapsat %s: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "nelze zkompilovat %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "%s byl úspěšně vytvořen"
msgid "usage: ikiwiki [options] source dest"
msgstr "použití: ikiwiki [volby] zdroj cíl"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "generuji obaly..."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "znovu vytvářím wiki..."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "obnovuji wiki..."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Diskuse"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr "Při použití --cgi musíte pomocí --url zadat url k wiki"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "Chyba"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:569
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1243
+#, fuzzy, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr "Byla rozpoznána smyčka direktivy %s na %s v hloubce %i"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
+#, fuzzy, perl-format
+msgid "cannot match pages: %s"
+msgstr "nemohu číst %s: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr ""
+
+#~ msgid "discussion"
+#~ msgstr "diskuse"
+
+#~ msgid "rendering %s"
+#~ msgstr "zpracovávám %s"
+
+#, fuzzy
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr "Při používání vyhledávacího modulu musíte zadat %s"
+
+#~ msgid "bad size \"%s\""
+#~ msgstr "chybná velikost \"%s\""
+
+#~ msgid "failed to find url in html"
+#~ msgstr "v html se nepodařilo nalézt url"
+
+#~ msgid "processed ok at %s"
+#~ msgstr "zpracováno ok %s"
+
+#~ msgid "Your password has been emailed to you."
+#~ msgstr "Vaše heslo vám bylo zasláno."
+
+#~ msgid "polygen failed"
+#~ msgstr "polygen selhal"
+
+#~ msgid "cleaning hyperestraier search index"
+#~ msgstr "čistím vyhledávací index hyperestraieru"
+
+#~ msgid "updating hyperestraier search index"
+#~ msgstr "aktualizuji vyhledávací index hyperestraieru"
+
#, fuzzy
#~ msgid ""
#~ "REV is not set, not running from mtn post-commit hook, cannot send "
#~ "REV není nastavena, není spuštěna ze svn post-commit, nemohu zaslat "
#~ "oznámení"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "aktualizace %s (%s) uživatelem %s"
-
#~ msgid "%s not found"
#~ msgstr "%s nenalezen"
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# Danish translations for ikiwiki package
+# Copyright (C) 2008 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
#
msgid ""
msgstr ""
-"Project-Id-Version: ikiwiki\n"
+"Project-Id-Version: ikiwiki 3.14159\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-11 00:48-0500\n"
-"PO-Revision-Date: 2008-02-11 00:12+0100\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
+"PO-Revision-Date: 2009-07-23 01:07+0200\n"
"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
-"Language-Team: Danish <dansk@klid.dk>\n"
+"Language-Team: None\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-Language: Danish\n"
"X-Poedit-Country: DENMARK\n"
"X-Poedit-SourceCharset: utf-8\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Du skal først logge på."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+"mulig opsætningsfejl: sslcookie er sat, men du forsøger at logge på via "
+"http, ikke https"
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
-msgstr "Pålogning fejlede, måske skal du tillade infokager (cookies)?"
+msgstr "Pålogning mislykkedes, måske skal du tillade infokager (cookies)?"
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr "Din kørsel (login session) er udløbet"
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr "Pålogning"
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
msgid "Preferences"
msgstr "Indstillinger"
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr "Admin"
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Indstillinger gemt"
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "%s er ikke en redigérbar side"
-
-#: ../IkiWiki/CGI.pm:384 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:242 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:176
-msgid "discussion"
-msgstr "diskussion"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Du er banlyst."
-#: ../IkiWiki/CGI.pm:431
-#, perl-format
-msgid "creating %s"
-msgstr "opretter %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Fejl"
-#: ../IkiWiki/CGI.pm:449 ../IkiWiki/CGI.pm:467 ../IkiWiki/CGI.pm:477
-#: ../IkiWiki/CGI.pm:511 ../IkiWiki/CGI.pm:555
-#, perl-format
-msgid "editing %s"
-msgstr "redigerer %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr "Indsamling udløst via web."
-#: ../IkiWiki/CGI.pm:644
-msgid "You are banned."
-msgstr "Du er banlyst."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr "Intet at gøre lige nu, alle fødninger er tidssvarende!"
-#: ../IkiWiki/Plugin/aggregate.pm:101
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr "mangler parametren %s"
-#: ../IkiWiki/Plugin/aggregate.pm:128
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "ny fødning"
-#: ../IkiWiki/Plugin/aggregate.pm:142
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "indlæg"
-#: ../IkiWiki/Plugin/aggregate.pm:144
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "nyt"
-#: ../IkiWiki/Plugin/aggregate.pm:309
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "udløber %s (%s dage gammel)"
-#: ../IkiWiki/Plugin/aggregate.pm:316
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "udløber %s"
-#: ../IkiWiki/Plugin/aggregate.pm:345
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "korrekt dannet ved %s"
+msgid "last checked %s"
+msgstr "senest undersøgt %s"
-#: ../IkiWiki/Plugin/aggregate.pm:349
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "undersøger fødning %s ..."
-#: ../IkiWiki/Plugin/aggregate.pm:354
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "kunne ikke finde fødning ved %s"
-#: ../IkiWiki/Plugin/aggregate.pm:369
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
msgstr "fødning ikke fundet"
-#: ../IkiWiki/Plugin/aggregate.pm:380
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr "(defekt UTF-8 fjernet fra fødning)"
-#: ../IkiWiki/Plugin/aggregate.pm:386
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr "(fødningselementer omgået (escaped))"
-#: ../IkiWiki/Plugin/aggregate.pm:392
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "fødning fik XML::Feed til at bryde sammen!"
-#: ../IkiWiki/Plugin/aggregate.pm:466
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "opretter ny side %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr "sletter bundt.."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "færdig"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr "Skal angive %s"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Oprettelse af bundt i S3 mislykkedes: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Arkivering af fil i S3 mislykkedes: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "Sletning af fil fra S3 mislykkedes: "
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr "der er allerede en side ved navn %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr "forhindret af allowed_attachments"
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr "dårligt vedhæftningsfilnavn"
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr "vedhæftningsoplægning"
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr "automatisk indeks-dannelse"
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+"Beklager, men det ligner spam til <a href=\"http://blogspam.net/\">blogspam</"
+"a>: "
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr "%s fra %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "Ingen henvisninger der ikker fungerer!"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr "Ikke-understøttet sideformat %s"
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr "kommentar skal have indhold"
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr "Anonym"
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr "dårligt sidenavn"
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, perl-format
+msgid "commenting on %s"
+msgstr "kommenterer på %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr "siden '%s' eksisterer ikke, så du kan ikke kommentere"
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr "kommentarer på side '%s' er lukket"
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr "kommentar gemt for moderering"
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr "Din kommentar vil blive tilføjet efter moderatorgenemsyn"
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr "Tilføjede en kommentar"
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr "Tilføjede en kommentar: %s"
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr "du er ikke logget på som en administrator"
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr "Kommentarmoderering"
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr "kommentarkoderering"
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr "Kommentarer"
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr "parametren %s er krævet"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr "ingen tekst blev kopieret i denne side"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr "ingen tekst blev kopieret i denne side med id %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, perl-format
+msgid "removing old preview %s"
+msgstr "fjerner gammelt smugkig %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "%s er ikke en redigérbar side"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "opretter %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "redigerer %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
msgid "template not specified"
msgstr "skabelon %s ikke angivet"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
msgid "match not specified"
msgstr "sammenligning ikke angivet"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr "redigeringsskabelon %s registreret for %s"
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
msgid "failed to process"
msgstr "dannelsen mislykkedes"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr "skal angive format og tekst"
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "spådom (fortune) fejlede"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
-msgstr "lokalisering af url i html mislykkedes"
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+msgid "missing page"
+msgstr "manglende side"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr "Siden %s eksisterer ikke."
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+#, fuzzy
+msgid "not a page"
+msgstr "kan ikke få sider til at passe sammen: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, fuzzy, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "%s er ikke en redigérbar side"
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr "Du har ikke lov til at ændre %s"
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr "du kan ikke påvirke en fil med modus %s"
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr "du har ikke lov til at ændre modus for filer"
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Skal angive %s når udvidelsen %s bruges"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr "Tolkning af URL mislykkedes, kan ikke afgøre domænenavn"
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
msgstr "graphviz-kørsel mislykkedes"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "prog er ikke et gyldigt graphviz-program"
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr "tohighlight indeholder ukendt filtype '%s'"
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr "Kildekode: %s"
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+"advarsel: highlight perl modul ikke tilgængelig: falder tilbage til simpel "
+"gennemkørsel"
+
+#: ../IkiWiki/Plugin/img.pm:63
+msgid "Image::Magick is not installed"
+msgstr "Image::Magick ikke installeret"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
-msgstr "forkert størrelse \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr "forkert størrelsesformat \"%s\" (burde være WxH)"
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr "læsning af %s mislykkedes: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
msgstr "Ændring af størrelse mislykkedes: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, perl-format
msgid "failed to determine size of image %s"
-msgstr "Vurdering af størrelse på billede mislykkedes: %s"
+msgstr "Vurdering af billedstørrelse mislykkedes: %s"
-#: ../IkiWiki/Plugin/inline.pm:44
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr "Skal angive url til wiki med --url når --rss eller --atom anvendes"
-#: ../IkiWiki/Plugin/inline.pm:136
+#: ../IkiWiki/Plugin/inline.pm:138
+msgid "page editing not allowed"
+msgstr "sideredigering er ikke tilladt"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+msgid "missing pages parameter"
+msgstr "mangler pages-parametren"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr "Sort::Naturally krævet for title_natural sortering"
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "ukendt sorteringsform %s"
-#: ../IkiWiki/Plugin/inline.pm:201
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr "Tilføj nyt indlæg med følgende titel:"
-#: ../IkiWiki/Plugin/inline.pm:217
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr "ikke-eksisterende skabelon: %s"
-#: ../IkiWiki/Plugin/inline.pm:250 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Diskussion"
-
-#: ../IkiWiki/Plugin/inline.pm:468
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "RPC::XML::Client ikke fundet, pinger ikke"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr "dot-kørsel mislykkedes"
-#: ../IkiWiki/Plugin/lockedit.pm:29
+#: ../IkiWiki/Plugin/lockedit.pm:47
#, perl-format
-msgid "%s is locked by %s and cannot be edited"
-msgstr "%s er låst af %s og kan ikke redigeres"
+msgid "%s is locked and cannot be edited"
+msgstr "%s er låst og kan ikke redigeres"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+"multimarkdown er aktiveret, men Text::MultiMarkdown er ikke installeret"
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"Indlæsning af perl-modulet Markdown.pm (%s) eller /usr/bin/markdown (%s) "
"mislykkedes"
-#: ../IkiWiki/Plugin/meta.pm:132
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr "stilsnit (stylesheet) ikke fundet"
-#: ../IkiWiki/Plugin/meta.pm:158
+#: ../IkiWiki/Plugin/meta.pm:196
msgid "redir page not found"
msgstr "henvisningsside ikke fundet"
-#: ../IkiWiki/Plugin/meta.pm:171
+#: ../IkiWiki/Plugin/meta.pm:210
msgid "redir cycle is not allowed"
msgstr "ring af henvisninger er ikke tilladt"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Spejle"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Spejl"
msgid "more"
msgstr "mere"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime ikke implementeret"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr "Log på med"
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Skaf en OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
-msgstr "Alle sider henvises til fra andre sider."
+#: ../IkiWiki/Plugin/orphans.pm:45
+msgid "All pages have other pages linking to them."
+msgstr "Alle sider har henvisninger fra andre sider."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr "dårlig eller manglende skabelon"
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Konto korrekt oprettet. Nu kan du logge på."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Fejl ved kontooprettelse."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+"Ingen emailadresse, så kan ikke sende adgangskodenulstillingsinstruktioner."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Afsendelse af mail mislykkedes"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Din adgangskode er blevet sendt til dig."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr "Du har fået tilsendt adgangskodenulstillingsinstruktioner."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr "Ukorrekt adgangskodenumstillings-URL"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr "adgangskodenulstilling afvist"
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr "Ping modtaget."
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr "kræver 'from'- og 'to'-parametre"
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, perl-format
+msgid "Will ping %s"
+msgstr "vil pinge %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr "ignorerer ping-direktiv for wiki %s (denne wiki er %s)"
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+msgid "LWP not found, not pinging"
+msgstr "LWP ikke fundet, pinger ikke"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s er ikke en gyldig sprogkode"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+"%s er ikke en gyldig værdi for po_link_to, falder tilbage til "
+"po_link_to=default"
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+"po_link_to=negotiated kræver at usedirs er aktiveret, falder tilbage til "
+"po_link_to=default"
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr "gendanner alle sider for at korrigere meta titler"
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, perl-format
+msgid "building %s"
+msgstr "danner %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr "opdaterer PO-filer"
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+"Kan ikke fjerne en oversættelse. Fjern i stedet hovedsiden, så fjernes dens "
+"oversættelser også."
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+"Kan ikke omdøbe en oversættelse. Omdøb i stedet hovedsiden, så omdøbes dens "
+"oversættelser også."
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr "POT-filen %s eksisterer ikke"
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "kopiering af POT-filen til %s mislykkedes"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, perl-format
+msgid "failed to update %s"
+msgstr "opdatering af %s mislykkedes"
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:858
+#, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "kopiering af POT-filen til %s mislykkedes"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr "N/A"
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, perl-format
+msgid "failed to translate %s"
+msgstr "oversættelse af %s mislykkedes"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr "forældede PO filer fjernet"
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, perl-format
+msgid "failed to write %s"
+msgstr "skrivning af %s mislykkedes"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+msgid "failed to translate"
+msgstr "oversættelse mislykkedes"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, perl-format
+msgid "failed to read %s"
+msgstr "læsning af %s mislykkedes"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+"forkert gettext-data, gå tilbage til forrige side og fortsæt redigering"
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "stem"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Samlede stemmer:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "polygen ikke installeret"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "polygen fejlede"
+#: ../IkiWiki/Plugin/polygen.pm:60
+msgid "command failed"
+msgstr "kommando fejlede"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "manglende formular"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "ukendt formular"
msgid "%A night"
msgstr "%A nat"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "ved tetid %A"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "ved midnat"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "midt på dagen %A"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
-msgid "missing page"
-msgstr "manglende side"
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr "ugyldig procentværdi %s"
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr "Kræver enten parametre `percent` eller `totalpages og `donepages`"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr "(Diff trunkeret)"
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
#, perl-format
-msgid "The page %s does not exist."
-msgstr "Siden %s eksisterer ikke."
+msgid "%s does not exist"
+msgstr "%s eksisterer ikke"
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/remove.pm:38
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Skal angive %s når søgeudvidelsen bruges"
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s er ikke i srcdir, så kan ikke blive slettet"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr "%s er ikke en fil"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr "bekræft at %s bliver fjernet"
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr "Vælg vedhæftning der skal slettes."
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr "fjernet"
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr "%s er ikke i srcdir, så kan ikke blive omdøbt"
+
+#: ../IkiWiki/Plugin/rename.pm:62
+msgid "no change to the file name was specified"
+msgstr "ingen ændring til filnavnet blev angivet"
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "renser hyperestraier søgeindeks"
+#: ../IkiWiki/Plugin/rename.pm:68
+#, perl-format
+msgid "illegal name"
+msgstr "ugyldigt navn"
+
+#: ../IkiWiki/Plugin/rename.pm:73
+#, perl-format
+msgid "%s already exists"
+msgstr "%s eksisterer allerede"
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr "%s eksisterer allerede på disken"
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, perl-format
+msgid "rename %s"
+msgstr "omdøb %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr "Omdøb også UnderSider og vedhæftninger"
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr "Kun en vedhæftning kan blive omdøbt ad gangen."
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr "Vælg vedhæftningen som skal omdøbes."
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr "omdøb %s til %s"
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, perl-format
+msgid "update for rename of %s to %s"
+msgstr "opdatering til omdøbning af %s til %s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr "behøver Digest::SHA1 til indeks %s"
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "opdaterer hyperestraier søgeindeks"
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr "søg"
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
-msgstr "genvejsudvidelsen vil ikke fungere uden en shortcuts.mdwn"
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr "genvejsudvidelsen vil ikke fungere uden %s"
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr "manglende navn eller url parameter"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "genvej %s viser til <i>%s</i>"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
msgstr "afkodning af smileys mislykkedes"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
msgstr "afkodningsfejl"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
-msgstr "dårlig featurepoint-parameter diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
+msgstr "forkert featurepoint-parameter diameter"
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
-msgstr "dårlig featurepoint-parameter location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
+msgstr "forkert featurepoint-parameter location"
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "manglende værdier"
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+msgid "invalid height value"
msgstr "forkert højdeværdi"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
msgstr "manglende breddeparameter"
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+msgid "invalid width value"
msgstr "forkert breddeværdi"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr "php-kørsel mislykkedes"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "kan ikke finde fil"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "ukendt dataformat"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr "blanke data"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "Direkte datanedlastning"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
msgstr "afkodningsfejl på linje %d: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
msgstr "manglende id-parameter"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "skabelon %s ikke fundet"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
msgstr "dannelsen mislykkedes:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr "manglende tex-kode"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr "kode indeholder ikke-tilladte latec-kommandoer"
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
msgid "failed to generate image from code"
msgstr "billedopbygning fra kode mislykkedes"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
-msgstr "(kan ikke omskiftes i et smugkig)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
+msgstr "udvidelse"
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "getctime ikke implementeret"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr "aktivér %s?"
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr "opsætningsfilen for denne wiki er ukendt"
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr "primær"
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr "udvidelser"
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+"Opsætningsændringerne vist nedenfor kræver wiki-genopbygning for at træde i "
+"kraft."
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+"For at opsætningsændringerne vist nedenfor træder fuldt ud i kraft, skal du "
+"muligvis genopbygge wikien."
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr "Fejl: %s returnerede ikke-nul (%s). Dropper opsætningsændringer."
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr "kan ikke afgøre id for ikke-tillidsfulde skribent %s"
-#: ../IkiWiki/Render.pm:274 ../IkiWiki/Render.pm:295
+#: ../IkiWiki/Receive.pm:85
+#, perl-format
+msgid "bad file name %s"
+msgstr "dårligt filnavn %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+"symbolsk lænke fundet i srcdir-sti (%s) -- sæt allow_symlinks_before_srcdir "
+"for at tillade dette"
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "udelader forkert filnavn %s"
-#: ../IkiWiki/Render.pm:350
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr "%s har flere mulige kildesider"
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "fjerner gammel side %s"
-#: ../IkiWiki/Render.pm:391
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "gennemlæser %s"
-#: ../IkiWiki/Render.pm:396
+#: ../IkiWiki/Render.pm:447
#, perl-format
-msgid "rendering %s"
-msgstr "danner %s"
-
-#: ../IkiWiki/Render.pm:417
-#, perl-format
-msgid "rendering %s, which links to %s"
+msgid "building %s, which links to %s"
msgstr "danner %s, som henviser til %s"
-#: ../IkiWiki/Render.pm:438
+#: ../IkiWiki/Render.pm:468
#, perl-format
-msgid "rendering %s, which depends on %s"
+msgid "building %s, which depends on %s"
msgstr "danner %s, som afhænger af %s"
-#: ../IkiWiki/Render.pm:477
+#: ../IkiWiki/Render.pm:507
#, perl-format
-msgid "rendering %s, to update its backlinks"
+msgid "building %s, to update its backlinks"
msgstr "danner %s, for at opdatere dens krydshenvisninger (backlinks)"
-#: ../IkiWiki/Render.pm:489
+#: ../IkiWiki/Render.pm:519
#, perl-format
-msgid "removing %s, no longer rendered by %s"
+msgid "removing %s, no longer built by %s"
msgstr "fjerner %s, ikke længere dannet af %s"
-#: ../IkiWiki/Render.pm:515
+#: ../IkiWiki/Render.pm:543
#, perl-format
-msgid "ikiwiki: cannot render %s"
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: kan ikke danne %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "kan ikke læse %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "bygger wrappers.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr "du skal angive et wikinavn (som indeholder alfanumeriske tegn)"
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "genopbygger wiki..."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr "revisionskontrolsystem %s ikke understøttet"
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "genopfrisker wiki..."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr "opsætning af depotet med ikiwiki-makerepo mislykkedes"
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "færdig"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr "** Deaktiverer udvidelse %s, da den fejler med denne besked:"
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "wrapper-navn ikke angivet"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "skrivning ad %s mislykkedes: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "kompilering af %s mislykkedes"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "Korrekt bygget %s"
msgid "usage: ikiwiki [options] source dest"
msgstr "brug: ikiwiki [valg] kilde mål"
-#: ../ikiwiki.in:82
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr " ikiwiki --setup opsætningsfil"
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr "brug: --set var=værdi"
-#: ../IkiWiki.pm:130
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "bygger wrappers.."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "genopbygger wiki..."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "genopfrisker wiki..."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Diskussion"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr "Skal angive url til wiki med --url når der bruges --cgi"
-#: ../IkiWiki.pm:217 ../IkiWiki.pm:218
-msgid "Error"
-msgstr "Fejl"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr "kan ikke bruge flere samtidige RCS-udvidelser"
+
+#: ../IkiWiki.pm:569
+#, perl-format
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+"indlæsning af ekstern udvidelse krævet af udvidelsen %s mislykkedes: %s"
+
+#: ../IkiWiki.pm:1243
+#, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
+msgstr "forudberegningssløkke fundet på %s ved dybde %i"
+
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr "ja"
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:772
+#: ../IkiWiki.pm:1915
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
-msgstr "%s forudberegningssløkke fundet på %s ved dybde %i"
+msgid "cannot match pages: %s"
+msgstr "kan ikke få sider til at passe sammen: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr "Hvad skal wikien hedde?"
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr "wiki"
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr "Hvilket revisionskontrolsystem skal bruges?"
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr "Hvilken bruger (wiki konto eller openid) skal være administrator?"
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr "Hvad er webserverens domænenavn?"
+
+#~ msgid "discussion"
+#~ msgstr "diskussion"
# German translation of the ikiwiki language file resulting in de.po
# Copyright © 2008 Kai Wasserbäch <debian@carbon-project.org>
+# Copyright © 2008-2009 Kurt Gramlich <kurt@skolelinux.de>
# This file is distributed under the same license as the ikiwiki package.
#
msgid ""
msgstr ""
-"Project-Id-Version: ikiwiki 2.40\n"
-"Report-Msgid-Bugs-To: ikiwiki@packages.debian.org\n"
-"POT-Creation-Date: 2008-02-24 16:02-0500\n"
-"PO-Revision-Date: 2008-03-03 21:22+0100\n"
-"Last-Translator: Kai Wasserbäch <debian@carbon-project.org>\n"
+"Project-Id-Version: ikiwiki 3.14159\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
+"PO-Revision-Date: 2009-07-23 01:07+0100\n"
+"Last-Translator: Kurt Gramlich <kurt@skolelinux.de>\n"
"Language-Team: German <debian-l10n-german@lists.debian.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Sie müssen sich zuerst anmelden."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+"vermutliche Fehlkonfiguration: sslcookie ist gesetzt, aber Sie versuchen "
+"sich via http anzumelden, nicht https"
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
-msgstr "Anmeldung fehlgeschlagen, möglicherweise müssen Sie zuvor Cookies aktivieren?"
+msgstr ""
+"Anmeldung fehlgeschlagen, möglicherweise müssen Sie zuvor Cookies aktivieren?"
+
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr "Ihre Anmeldezeit ist abgelaufen."
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr "Anmelden"
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
msgid "Preferences"
msgstr "Einstellungen"
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr "Administrator"
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Einstellungen gespeichert."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "%s ist keine bearbeitbare Seite"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Sie sind ausgeschlossen worden."
-#: ../IkiWiki/CGI.pm:384 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:237 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:172
-msgid "discussion"
-msgstr "Diskussion"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Fehler"
-#: ../IkiWiki/CGI.pm:440
-#, perl-format
-msgid "creating %s"
-msgstr "erstelle %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr "Das Web löst die Zusammenstellung aus"
-#: ../IkiWiki/CGI.pm:458 ../IkiWiki/CGI.pm:476 ../IkiWiki/CGI.pm:486
-#: ../IkiWiki/CGI.pm:520 ../IkiWiki/CGI.pm:564
-#, perl-format
-msgid "editing %s"
-msgstr "bearbeite %s"
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr "Es gibt nichts zu tun, alle Vorlagen (feeds) sind aktuell!"
-#: ../IkiWiki/CGI.pm:653
-msgid "You are banned."
-msgstr "Sie sind ausgeschlossen worden."
-
-#: ../IkiWiki/Plugin/aggregate.pm:101
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr "Parameter %s fehlt"
-#: ../IkiWiki/Plugin/aggregate.pm:128
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
-msgstr "neuer Feed"
+msgstr "neue Vorlage (feed)"
-#: ../IkiWiki/Plugin/aggregate.pm:142
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "Beiträge"
-#: ../IkiWiki/Plugin/aggregate.pm:144
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "neu"
-#: ../IkiWiki/Plugin/aggregate.pm:309
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "%s läuft aus (%s Tage alt)"
-#: ../IkiWiki/Plugin/aggregate.pm:316
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "%s läuft aus"
-#: ../IkiWiki/Plugin/aggregate.pm:345
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "normal verarbeitet um %s"
+msgid "last checked %s"
+msgstr "zuletzt geprüft %s"
-#: ../IkiWiki/Plugin/aggregate.pm:349
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
-msgstr "überprüfe Feed %s ..."
+msgstr "überprüfe Vorlage (feed) %s ..."
-#: ../IkiWiki/Plugin/aggregate.pm:354
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
-msgstr "konnte Feed unter %s nicht finden"
+msgstr "konnte Vorlage (feed) unter %s nicht finden"
-#: ../IkiWiki/Plugin/aggregate.pm:369
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
-msgstr "Feed nicht gefunden"
+msgstr "Vorlage (feed) nicht gefunden"
-#: ../IkiWiki/Plugin/aggregate.pm:380
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
-msgstr "(ungültiges UTF-8 wurde aus dem Feed entfernt)"
+msgstr "(ungültiges UTF-8 wurde aus der Vorlage (feed) entfernt)"
-#: ../IkiWiki/Plugin/aggregate.pm:386
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
-msgstr "(Feedentitäten maskiert)"
+msgstr "(Einträge in der Vorlage (feed) wurden maskiert)"
-#: ../IkiWiki/Plugin/aggregate.pm:392
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
-msgstr "Feed führte zum Absturz von XML::Feed!"
+msgstr "Vorlage (feed) führte zum Absturz von XML::Feed!"
-#: ../IkiWiki/Plugin/aggregate.pm:466
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "erstelle neue Seite %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr "lösche Behälter (bucket)..."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "fertig"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr "%s muss angegeben werden"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Konnte Behälter (bucket) in S3 nicht anlegen: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Konnte die Datei nicht in S3 speichern: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "Konnte die Datei nicht in S3 löschen: "
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr "eine Seite mit dem Namen %s existiert bereits"
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr "durch allowed_attachements verboten"
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr "fehlerhafter Dateiname für Anhang"
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr "Anhang hochladen"
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr "automatische Index-Erstellung"
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+"Entschuldigung, aber <a href=\"http://blogspam.net/\">blogspam</a> stuft das "
+"als Spam ein: "
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr "%s von %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
-msgstr "Es gibt keine ungültigen Links!"
+msgstr "Es gibt keine ungültigen Verweise!"
+
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr "nicht unterstütztes Seitenformat %s"
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr "ein Kommentar sollte Inhalt haben"
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr "Anonym"
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr "fehlerhafter Seitenname"
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, perl-format
+msgid "commenting on %s"
+msgstr "kommentiere %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+"Seite %s existiert nicht, Sie können sie deshalb auch nicht kommentieren"
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr "Kommentare zur Seite %s sind gesperrt"
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr "Der Kommentar wurde zur Moderation gespeichert"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr "Ihr Kommentar wird nach Moderation verschickt"
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr "Kommentar hinzugefügt"
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr "Kommentar hinzugefügt: %s"
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr "Sie sind nicht als Administrator angemeldet"
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr "Kommentar-Moderation"
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr "Kommentar-Moderation"
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr "Kommentare"
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr "der Parameter %s wird benötigt"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr "es wurde kein Text in diese Seite kopiert"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr "es wurde kein Text in diese Seite mit der id %s kopiert"
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, perl-format
+msgid "removing old preview %s"
+msgstr "entferne alte Vorschau %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "Seite %s kann nicht bearbeitet werden"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "erstelle %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "bearbeite %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
msgid "template not specified"
msgstr "Vorlage nicht angegeben"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
msgid "match not specified"
msgstr "Übereinstimmung nicht angegeben"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
-msgstr "»edittemplate« %s registriert für %s"
+msgstr "edittemplate %s für %s registriert"
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
msgid "failed to process"
-msgstr "Bearbeitung fehlgeschlagen"
+msgstr "Ablauf fehlgeschlagen"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr "Format und Text müssen spezifiziert werden"
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
-msgstr "»fortune« fehlgeschlagen"
+msgstr "fortune fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+msgid "missing page"
+msgstr "fehlende Seite"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr "Die Seite %s existiert nicht."
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
-msgstr "URL in HTML nicht gefunden"
+#: ../IkiWiki/Plugin/getsource.pm:73
+#, fuzzy
+msgid "not a page"
+msgstr "Kann die Seiten nicht zuordnen: %s"
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, fuzzy, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "Seite %s kann nicht bearbeitet werden"
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr "Sie dürfen %s nicht verändern"
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr "Sie können eine Datei mit den Zugriffsrechten %s nicht nutzen"
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr "Sie dürfen die Zugriffsrechte der Datei nicht ändern"
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "%s muss angegeben werden, wenn die %s Erweiterung verwandt wird"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr "auswerten der URL fehlgeschlagen, konnte Domainnamen nicht feststellen"
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
-msgstr "konnte graphviz nicht ausführen"
+msgstr "graphviz konnte nicht ausgeführt werden"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "prog ist kein gültiges graphviz-Programm"
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
#, perl-format
-msgid "bad size \"%s\""
-msgstr "falsche Größe \"%s\""
+msgid "tohighlight contains unknown file type '%s'"
+msgstr "tohighlight enteilt unbekannten Dateityp '%s'"
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr "Quellcode: %s"
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+"Warnung: das highlight Perlmodul ist nicht verfügbar; greife zurück auf pass "
+"through"
+
+#: ../IkiWiki/Plugin/img.pm:63
+msgid "Image::Magick is not installed"
+msgstr "Image::Magick ist nicht installiert"
+
+#: ../IkiWiki/Plugin/img.pm:72
+#, perl-format
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr "falsches Format in \"%s\" für size (sollte BxH sein)"
+
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr "Lesen von %s fehlgeschlagen: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
msgstr "Größenänderung fehlgeschlagen: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, perl-format
msgid "failed to determine size of image %s"
msgstr "Größe des Bildes %s konnte nicht festgestellt werden."
-#: ../IkiWiki/Plugin/inline.pm:44
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
-msgstr "Die URL zum Wiki muss mit --url angegeben werden, wenn --rss oder --atom genutzt wird"
+msgstr ""
+"Die URL zum Wiki muss mit --url angegeben werden, wenn --rss oder --atom "
+"genutzt wird"
+
+#: ../IkiWiki/Plugin/inline.pm:138
+msgid "page editing not allowed"
+msgstr "bearbeiten der Seiten nicht erlaubt"
-#: ../IkiWiki/Plugin/inline.pm:136
+#: ../IkiWiki/Plugin/inline.pm:155
+msgid "missing pages parameter"
+msgstr "fehlender Seitenparameter"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr "Sort::Naturally wird benötigt für title_natural sort"
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "Unbekannter Sortierungstyp %s"
-#: ../IkiWiki/Plugin/inline.pm:196
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr "Füge einen neuen Beitrag hinzu. Titel:"
-#: ../IkiWiki/Plugin/inline.pm:212
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr "nicht-vorhandene Vorlage %s"
-#: ../IkiWiki/Plugin/inline.pm:245 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Diskussion"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
-msgstr "RPC::XML::Client nicht gefunden, pinge nicht"
+msgstr "RPC::XML::Client nicht gefunden, führe Ping nicht aus"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr "dot konnte nicht ausgeführt werden"
-#: ../IkiWiki/Plugin/lockedit.pm:29
+#: ../IkiWiki/Plugin/lockedit.pm:47
#, perl-format
-msgid "%s is locked by %s and cannot be edited"
-msgstr "%s wurde von %s gesperrt und kann nicht bearbeitet werden"
+msgid "%s is locked and cannot be edited"
+msgstr "%s ist gesperrt und kann nicht bearbeitet werden"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+"multimarkdown ist eingeschaltet, aber Text::MultiMarkdown ist nicht "
+"installiert"
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
-msgstr "Laden des des Perl-Moduls »Markdown.pm« (%s) oder von »/usr/bin/markdown« (%s) fehlgeschlagen"
+msgstr ""
+"laden des Perlmoduls Markdown.pm (%s) oder /usr/bin/markdown (%s) "
+"fehlgeschlagen"
-#: ../IkiWiki/Plugin/meta.pm:132
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr "Stylesheet nicht gefunden"
-#: ../IkiWiki/Plugin/meta.pm:158
+#: ../IkiWiki/Plugin/meta.pm:196
msgid "redir page not found"
msgstr "Umleitungsseite nicht gefunden"
-#: ../IkiWiki/Plugin/meta.pm:171
+#: ../IkiWiki/Plugin/meta.pm:210
msgid "redir cycle is not allowed"
msgstr "Zyklische Umleitungen sind nicht erlaubt"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Spiegel"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Spiegel"
msgid "more"
msgstr "mehr"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime ist nicht implementiert"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr "Anmelden mit"
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Eine OpenID anfordern"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
-msgstr "Alle Seiten sind von anderen Seiten aus verlinkt."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
+msgstr "Alle Seiten haben mindenstens einen Verweis von einer anderen Seite."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr "fehlerhafte oder fehlende Vorlage"
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Kontoerstellung erfolgreich. Sie können sich jetzt anmelden."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Konto konnte nicht erstellt werden."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+"es gibt keine E-Mail Adresse, deshalb kann keine Anweisung zum Zurücksetzen "
+"des Passwortes zugeschickt werden."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Es konnte keine E-Mail versandt werden"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Ihr Passwort wurde Ihnen via E-Mail zugesandt."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr "Ihnen wurden Anweisungen zum Zurücksetzen des Passworts zugesandt."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr "fehlerhafte URL zum Zurücksetzen des Passworts"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr "zurücksetzen des Passworts abgelehnt"
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr "Ping empfangen."
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr "erfordert die Parameter 'from' und 'to'"
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, perl-format
+msgid "Will ping %s"
+msgstr "werde Ping an %s senden"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr "Ignoriere die ping Anweisung für das Wiki %s (dieses Wiki ist %s)"
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+msgid "LWP not found, not pinging"
+msgstr "LWP nicht gefunden, führe Ping nicht aus"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s ist keine gültige Sprachkodierung"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+"%s ist kein gültiger Wert für po_link_to, greife zurück auf "
+"po_link_to=default"
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+"po_link_to=negotiated benötigt usedirs eingeschaltet, greife zurück auf "
+"po_link_to=default"
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr "um die meta-titeln zu reparieren werden alle Seiten neu erstellt"
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, perl-format
+msgid "building %s"
+msgstr "erzeuge %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr "PO-Dateien aktualisiert"
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+"Übersetzung kann nicht entfernt werden. Wenn die Master Seite entfernt wird, "
+"werden auch ihre Übersetzungen entfernt."
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+"Eine Übersetzung kann nicht umbenannt werden. Wenn die Master Seite "
+"unbenannt wird, werden auch ihre Übersetzungen unbenannt."
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr "POT-Datei (%s) existiert nicht"
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "kopieren der POT-Datei nach %s fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, perl-format
+msgid "failed to update %s"
+msgstr "aktualisieren von %s fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "kopieren der POT-Datei nach %s fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr "N/A"
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, perl-format
+msgid "failed to translate %s"
+msgstr "übersetzen von %s fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr "überflüssige PO-Dateien wurden entfernt"
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, perl-format
+msgid "failed to write %s"
+msgstr "schreiben von %s fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+msgid "failed to translate"
+msgstr "übersetzen fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, perl-format
+msgid "failed to read %s"
+msgstr "lesen von %s fehlgeschlagen"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+"ungültige gettext Datei, gehe zurück zur vorherigen Seite um weiter zu "
+"arbeiten"
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "abstimmen"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Alle Stimmen:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "polygen ist nicht installiert"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "polygen fehlgeschlagen"
+#: ../IkiWiki/Plugin/polygen.pm:60
+msgid "command failed"
+msgstr "Befehl fehlgeschlagen"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "fehlende Formel"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "unbekannte Formel"
#. translators: %A- is the name of the previous day.
#: ../IkiWiki/Plugin/prettydate.pm:15
msgid "late %A- night"
-msgstr "spät am %A- in der Nacht"
+msgstr "%A- spät in der Nacht"
#: ../IkiWiki/Plugin/prettydate.pm:17
msgid "in the wee hours of %A- night"
-msgstr "in den frühen Morgenstunden %A-"
+msgstr "%A- in den frühen Morgenstunden"
#: ../IkiWiki/Plugin/prettydate.pm:20
msgid "terribly early %A morning"
#: ../IkiWiki/Plugin/prettydate.pm:29
msgid "%A afternoon"
-msgstr "am %A Nachmittag"
+msgstr "%A am Nachmittag"
#: ../IkiWiki/Plugin/prettydate.pm:32
msgid "late %A afternoon"
msgid "%A night"
msgstr "%A Nacht"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "zur Teezeit am %A"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "um Mitternacht"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "am Nachmittag des %A"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
-msgid "missing page"
-msgstr "fehlende Seite"
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr "unzulässiger Prozentwert %s"
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+"es werden entweder `percent` oder `totalpages` und `donepages` Parameter "
+"benötigt"
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr "(Diff wurde gekürzt)"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
#, perl-format
-msgid "The page %s does not exist."
-msgstr "Die Seite %s exisitiert nicht."
+msgid "%s does not exist"
+msgstr "%s existiert nicht"
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s ist nicht im srcdir und kann deshalb nicht gelöscht werden"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr "%s ist keine Datei"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr "bestätigen Sie die Entfernung von %s"
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr "Bitte wählen Sie die zu entfernenden Anhänge aus."
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr "entfernt"
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr "%s ist nicht im srcdir und kann deshalb nicht umbenannt werden"
+
+#: ../IkiWiki/Plugin/rename.pm:62
+msgid "no change to the file name was specified"
+msgstr "es wurde keine Änderung des Dateinamens angegeben"
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "%s muss angegeben werden, wenn die Sucherweiterung verwandt wird"
+msgid "illegal name"
+msgstr "unzulässiger Name"
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "bereinige hyperestraier-Suchindex"
+#: ../IkiWiki/Plugin/rename.pm:73
+#, perl-format
+msgid "%s already exists"
+msgstr "%s existiert bereits"
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr "%s existiert bereits auf der Festplatte"
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, perl-format
+msgid "rename %s"
+msgstr "benenne %s um"
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "aktualisiere hyperestraier-Suchindex"
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr "Auch Unterseiten (SubPages) und Anhänge umbenennen"
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
-msgstr "das »shortcut«-Plugin funktioniert nicht ohne eine »shortcuts.mdwn«"
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr "Es kann immer nur ein Anhang gleichzeitig umbenannt werden."
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr "Bitte wählen Sie den Anhang aus, der umbenannt werden soll."
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr "benenne %s in %s um"
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, perl-format
+msgid "update for rename of %s to %s"
+msgstr "aktualisiert zum Umbenennen von %s nach %s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr "benötige Digest::SHA1 um einen Index von %s zu erstellen"
+
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr "suchen"
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr "die shortcut Erweiterung wird ohne %s nicht funktionieren"
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr "fehlender Name oder URL-Parameter"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
-msgstr "Shortcut %s zeigt auf <i>%s</i>"
+msgstr "Tastenkürzel %s verweist nach <i>%s</i>"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
-msgstr "Smileys konnten nicht geparst werden"
+msgstr "Smileys konnten nicht ausgewertet werden"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
-msgstr "Parse-Fehler"
+msgstr "Auswertungsfehler"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
-msgstr "fehlerhafter »featurepoint«-Durchmesser"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
+msgstr "ungültiger featurepoint diameter"
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
-msgstr "fehlerhafter »featurepoint«-Ort"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
+msgstr "ungültige featurepoint location"
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "fehlende Werte"
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
-msgstr "fehlerhafte Höhenangaben"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+msgid "invalid height value"
+msgstr "ungültige Wert für height"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
-msgstr "fehlender Breitenparameter"
+msgstr "fehlender Parameter für width"
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
-msgstr "fehlerhafte Breitenangabe"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+msgid "invalid width value"
+msgstr "ungültige Wert für width"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr "konnte PHP nicht ausführen"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "konnte Datei nicht finden"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "unbekanntes Datenformat"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr "keine Daten"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "Direkter Daten-Download"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
-msgstr "Parse-Fehler in Zeile %d: %s"
+msgstr "Auswertungsfehler in Zeile %d: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
-msgstr "fehlender »id«-Parameter"
+msgstr "fehlender Parameter id"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "Vorlage %s nicht gefunden"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
-msgstr "Verarbeitung fehlgeschlagen von:"
+msgstr "Fehler beim Ablauf:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr "fehlender TeX-Code"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr "Code enthält verbotene LaTeX-Befehle"
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
msgid "failed to generate image from code"
msgstr "konnte kein Bild aus dem Code erzeugen"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
-msgstr "(nicht aus-/einklappbar im Vorschaumodus)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
+msgstr "Erweiterung"
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "getctime ist nicht implementiert"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr "%s aktivieren?"
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr "Die Einrichtungsdatei für dieses Wiki ist unbekannt"
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr "Hauptseite"
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr "Erweiterungen"
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+"Die unten aufgeführten Konfigurationsänderungen erfordern ein Neubau des "
+"Wikis, um wirksam zu werden."
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+"Damit die unten aufgeführten Konfigurationsänderungen insgesamt wirksam "
+"werden, kann es notwendig sein, das Wikis neu zu bauen."
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+"Fehler: %s endet mit nicht Null (%s). Die Änderungen an der Konfiguration "
+"wurden verworfen."
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+"id des nicht vertrauenswürdigen Absenders %s konnte nicht feststellt werden"
+
+#: ../IkiWiki/Receive.pm:85
+#, perl-format
+msgid "bad file name %s"
+msgstr "fehlerhafter Dateiname %s"
-#: ../IkiWiki/Render.pm:279 ../IkiWiki/Render.pm:300
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+"symbolischer Verweis im srcdir Pfad (%s) gefunden -- setzen Sie "
+"allow_symlinks_before_srcdir, um dies zu erlauben"
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "überspringe fehlerhaften Dateinamen %s"
-#: ../IkiWiki/Render.pm:355
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr "%s hat mehrere mögliche Quellseiten"
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "entferne alte Seite %s"
-#: ../IkiWiki/Render.pm:396
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "durchsuche %s"
-#: ../IkiWiki/Render.pm:401
-#, perl-format
-msgid "rendering %s"
-msgstr "erzeuge %s"
-
-#: ../IkiWiki/Render.pm:422
+#: ../IkiWiki/Render.pm:447
#, perl-format
-msgid "rendering %s, which links to %s"
-msgstr "erzeuge %s, was auf %s verweist"
+msgid "building %s, which links to %s"
+msgstr "erzeuge %s, die auf %s verweist"
-#: ../IkiWiki/Render.pm:443
+#: ../IkiWiki/Render.pm:468
#, perl-format
-msgid "rendering %s, which depends on %s"
-msgstr "erzeuge %s, das von %s abhängt"
+msgid "building %s, which depends on %s"
+msgstr "erzeuge %s, die von %s abhängt"
-#: ../IkiWiki/Render.pm:482
+#: ../IkiWiki/Render.pm:507
#, perl-format
-msgid "rendering %s, to update its backlinks"
-msgstr "erzeuge %s, um dessen Rücklinks zu aktualisieren"
+msgid "building %s, to update its backlinks"
+msgstr "erzeuge %s, um dessen Rückverweise zu aktualisieren"
-#: ../IkiWiki/Render.pm:494
+#: ../IkiWiki/Render.pm:519
#, perl-format
-msgid "removing %s, no longer rendered by %s"
+msgid "removing %s, no longer built by %s"
msgstr "entferne %s, wird nicht länger von %s erzeugt"
-#: ../IkiWiki/Render.pm:520
+#: ../IkiWiki/Render.pm:543
#, perl-format
-msgid "ikiwiki: cannot render %s"
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: kann %s nicht erzeugen"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "kann %s nicht lesen: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "erzeuge Wrapper.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
+"Sie müssen einen Wiki-Namen eingeben (der alphanumerische Zeichen enthält)"
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "erzeuge Wiki neu.."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr "nicht unterstütztes Versionskontrollsystem %s"
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "aktualisiere Wiki.."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr "erstellen des Depots mit ikiwiki-makerepo ist fehlgeschlagen"
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "fertig"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
+"** Erweiterung %s wurde ausgeschaltet, weil sie mit der folgenden Meldung "
+"fehlgeschlagen ist:"
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "Dateiname des Wrappers nicht angegeben"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "schreiben von %s fehlgeschlagen: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "erzeugen von %s fehlgeschlagen"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "%s wurde erfolgreich erstellt"
#: ../ikiwiki.in:13
msgid "usage: ikiwiki [options] source dest"
-msgstr "Benutzung: ikiwiki [Optionen] Quelle Ziel"
+msgstr "Aufruf: ikiwiki [Optionen] Quelle Ziel"
+
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr " ikiwiki --setup Konfigurationsdatei"
-#: ../ikiwiki.in:82
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
-msgstr "Benutzung: --set Variable=Wert"
+msgstr "Aufruf: --set Variable=Wert"
+
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "erzeuge Wrapper.."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "erzeuge Wiki neu.."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "aktualisiere Wiki.."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Diskussion"
-#: ../IkiWiki.pm:115
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
-msgstr "Es muss eine URL zum Wiki mit --url angegeben werden, wenn --cgi verwandt wird"
+msgstr ""
+"Es muss eine URL zum Wiki mit --url angegeben werden, wenn --cgi verwandt "
+"wird"
-#: ../IkiWiki.pm:184 ../IkiWiki.pm:185
-msgid "Error"
-msgstr "Fehler"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
+"Es können nicht mehrere Versionskontrollsystem-Erweiterungen verwandt werden"
+
+#: ../IkiWiki.pm:569
+#, perl-format
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr "Laden der für %s benötigten externen Erweiterung fehlgeschlagen: %s"
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:735
+#: ../IkiWiki.pm:1243
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
-msgstr "Präprozessorschleife %s auf Seite %s in Tiefe %i erkannt"
+msgid "preprocessing loop detected on %s at depth %i"
+msgstr "Präprozessorschleife auf %s in Tiefe %i erkannt"
+
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr "ja"
+
+#: ../IkiWiki.pm:1915
+#, perl-format
+msgid "cannot match pages: %s"
+msgstr "Kann die Seiten nicht zuordnen: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr "Wie soll das Wiki heißen?"
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr "Wiki"
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr "Welches Versionskontrollsystem soll verwandt werden?"
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr "Wer (Wiki-Konto oder OpenID) soll Administrator sein?"
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr "Wie lautet der Domainname des Webservers?"
+
+#~ msgid "discussion"
+#~ msgstr "Diskussion"
+# translation of es.po to
# ikiwiki spanish translation
-# Copyright (C) 2007 The Free Software Foundation, Inc
+# Copyright (C) 2007, 2009 The Free Software Foundation, Inc
# This file is distributed under the same license as the ikiwiki package.
#
-# Víctor Moral <victor@taquiones.net>, 2007.
+# Víctor Moral <victor@taquiones.net>, 2007, 2009.
+# Victor Moral <victor@taquiones.net>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: es\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
-"PO-Revision-Date: 2008-03-06 11:07+0100\n"
-"Last-Translator: Víctor Moral <victor@taquiones.net>\n"
-"Language-Team: Spanish <es@li.org>\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
+"PO-Revision-Date: 2009-06-14 12:32+0200\n"
+"Last-Translator: Victor Moral <victor@taquiones.net>\n"
+"Language-Team: <en@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Antes es necesario identificarse."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+"probablemente algo está mal configurado: la característica 'sslcookie' está "
+"activa, pero está intentando registrarse en el sistema vía el protocolo "
+"'http' y no 'https'"
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
"registro fallido, ¿ tal vez necesita activar las cookies en el navegador ?"
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr "Su registro en el sistema ha expirado."
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr "Identificación"
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
msgid "Preferences"
msgstr "Preferencias"
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr "Administración"
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Las preferencias se han guardado."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "la página %s no es modificable"
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "comentarios"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Ha sido expulsado."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "creando página %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Error"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "modificando página %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr "Contenido añadido activado vía web."
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "Ha sido expulsado."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
+"¡ No hay nada que hacer, todas las fuentes de noticias están actualizadas !"
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr "falta el parámetro %s"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "nueva entrada"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "entradas"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "nuevo"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "%s caducada (%s días de antigüedad)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "%s caducada"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "proceso completado con éxito a %s"
+msgid "last checked %s"
+msgstr "última comprobación el %s"
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "comprobando fuente de datos %s ..."
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "no puedo encontrar la fuente de datos en %s"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
msgstr "fuente de datos no encontrada"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr "(una secuencia UTF-8 inválida ha sido eliminada de la fuente de datos)"
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr "(los caracteres especiales de la fuente de datos están exceptuados)"
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "¡ la fuente de datos ha provocado un error fatal en XML::Feed !"
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "creando nueva página %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr "borrando el directorio.."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "completado"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr "Debe especificar %s"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Creación de directorio en S3 fallida: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "No puedo guardar el archivo en S3: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "No puedo borrar archivo en S3: "
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr "ya existe una página de nombre %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr "prohibido por la claúsula allowed_attachments"
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr "nombre de archivo adjunto erróneo"
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr "enviado el adjunto"
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr "creación de índice automática"
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+"Lo siento, pero el analizador <a href=\"http://blospam.net\">blogspam</a> "
+"dice que el texto puede ser spam."
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr "%s desde la página %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "¡ No hay enlaces rotos !"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr "formato de página %s no soportado"
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr "Un comentario debe tener algún contenido"
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr "Anónimo"
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr "nombre de página erróneo"
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, perl-format
+msgid "commenting on %s"
+msgstr "creando comentarios en la página %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr "la página '%s' no existe, así que no se puede comentar sobre ella"
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr "los comentarios para la página '%s' están cerrados"
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr "comentario guardado a la espera de aprobación"
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr "Su comentario será publicado después de que el moderador lo revise"
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr "Añadir un comentario"
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr "Comentario añadido: %s"
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr "No está registrado como un administrador"
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr "Aprobación de comentarios"
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr "aprobación de comentarios"
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr "Comentarios"
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr "el parámetro %s es obligatorio"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr "no se ha copiado ningún texto en esta página"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr "no se ha copiado ningún texto con el identificador %s en esta pagina"
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, perl-format
+msgid "removing old preview %s"
+msgstr "eliminando la antigua previsualización %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "la página %s no es modificable"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "creando página %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "modificando página %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
msgid "template not specified"
msgstr "falta indicar la plantilla (template)"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
msgid "match not specified"
msgstr "falta indicar la coincidencia de páginas (match)"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr "plantilla de edición %s registrada para %s"
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
msgid "failed to process"
msgstr "fallo en el proceso"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr "se deben especificar tanto el formato como el texto"
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "el programa fortune ha fallado"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+msgid "missing page"
+msgstr "página no encontrada"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr "No existe la página %s."
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+#, fuzzy
+msgid "not a page"
+msgstr "no encuentro páginas coincidentes: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, fuzzy, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "la página %s no es modificable"
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr "No puede cambiar %s"
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr "no puede actuar sobre un archivo con permisos %s"
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr "No puede cambiar los permisos de acceso de un archivo"
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Es obligatorio indicar %s cuando se utiliza el complemento de búsqueda"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
msgstr ""
-"El complemento googlecalendar no ha encontrado un URL en el código html "
+"Error en el análisis del URL, no puedo determinar el nombre del dominio"
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
msgstr "no he podido ejecutar el programa graphviz "
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "prog no es un programa graphviz válido "
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
#, perl-format
-msgid "bad size \"%s\""
-msgstr "tamaño erróneo \"%s\""
+msgid "tohighlight contains unknown file type '%s'"
+msgstr "la directiva tohighlight contiene el tipo de archivo desconocido '%s' "
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr "Código fuente: %s"
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+"aviso: el módulo Perl hightlight no está disponible; retrocedo la entrada "
+"para continuar el proceso. "
+
+#: ../IkiWiki/Plugin/img.pm:63
+msgid "Image::Magick is not installed"
+msgstr "El complemento Image::Magick no ha sido instalado"
+
+#: ../IkiWiki/Plugin/img.pm:72
+#, perl-format
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr "no puedo leer de %s: %s "
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
-msgstr "redimensionado fallido: %s"
+msgstr "dimensionamiento fallido: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, perl-format
msgid "failed to determine size of image %s"
msgstr "no he podido determinar el tamaño de la imagen %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
"Es obligatorio indicar un url al wiki cuando se usan los parámetros --rss ó "
"--atom"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+msgid "page editing not allowed"
+msgstr "no está permitida la modificación de páginas"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+msgid "missing pages parameter"
+msgstr "falta el parámetro pages"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+"Se necesita el módulo Sort::Naturally para el tipo de ordenación "
+"title_natural"
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "no conozco este tipo de ordenación %s"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr "Añadir una entrada nueva titulada:"
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr "la plantilla %s no existe "
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Comentarios"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "No he encontrado el componente RPC::XML::Client, no envío señal alguna"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr "no he podido ejecutar el programa dot"
-#: ../IkiWiki/Plugin/lockedit.pm:29
+#: ../IkiWiki/Plugin/lockedit.pm:47
#, perl-format
-msgid "%s is locked by %s and cannot be edited"
-msgstr "La página %s está bloqueada por %s y no puede modificarse"
+msgid "%s is locked and cannot be edited"
+msgstr "La página %s está bloqueada y no puede modificarse"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+"el modo multimarkdown está activo, pero no está instalado Text::MultiMarkdown"
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"no he podido cargar el módulo Perl Markdown.pm (%s) ó no he podido ejecutar "
"el programa /usr/bin/markdown (%s)"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr "hoja de estilo no encontrada "
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
msgid "redir page not found"
msgstr "falta la página a donde redirigir"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
msgid "redir cycle is not allowed"
msgstr "ciclo de redirección no permitido"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Réplicas"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Réplica"
msgid "more"
msgstr "ver más"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "la funcionalidad getctime no está incluida"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr "Identificarse mediante "
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Consiga un identificador OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "Todas las páginas están referenciadas entre sí."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr "plantilla errónea ó no existente"
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Cuenta de usuario creada con éxito. Ahora puede identificarse."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Error creando la cuenta de usuario."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+"No tengo dirección de correo electrónica, así que no puedo enviar "
+"instrucciones para reiniciar la contraseña"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "No he podido enviar el mensaje de correo electrónico"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Se le ha enviado su contraseña por correo electrónico."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+"Las instrucciones para reiniciar la contraseña se le han enviado por correo "
+"electrónico"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr "el url para reiniciar la contraseña es incorrecto"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr "reinicio de contraseña denegado"
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr "Recibida una señal ping."
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr "los parámetros 'from' y 'to' son obligatorios"
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, perl-format
+msgid "Will ping %s"
+msgstr "Informaremos a %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr "Ignorando directiva 'ping' para el wiki %s (este wiki es %s)"
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+msgid "LWP not found, not pinging"
+msgstr "No he encontrado el componente LWP, no envío señal alguna"
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, fuzzy, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s no es un archivo"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "Informaremos a %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, fuzzy, perl-format
+msgid "POT file (%s) does not exist"
+msgstr "No existe la página %s."
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "ha fallado la compilación del programa %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "ha fallado la compilación del programa %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "ha fallado la compilación del programa %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "dimensionamiento fallido: %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "dimensionamiento fallido: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "no he podido ejecutar el programa dot"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "no puedo leer de %s: %s "
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "Votar"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Recuento de votos:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "El complemento polygen no ha sido instalado"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "El programa polygen ha fallado"
+#: ../IkiWiki/Plugin/polygen.pm:60
+msgid "command failed"
+msgstr "la ejecución del programa ha fallado"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "falta la fórmula"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "fórmula desconocida "
msgid "%A night"
msgstr "la noche del %A"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "el %A a la hora del té"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "a medianoche"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "el %A a media tarde"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
-msgid "missing page"
-msgstr "página no encontrada"
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr "%s es un valor erróneo para un porcentaje"
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr "son necesarios los parámetros 'donepages' y 'percent' ó 'totalpages'"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr "(Lista de diferencias truncada)"
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
#, perl-format
-msgid "The page %s does not exist."
+msgid "%s does not exist"
msgstr "No existe la página %s."
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/remove.pm:38
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Es obligatorio indicar %s cuando se utiliza el complemento de búsqueda"
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s no está en el directorio fuente por lo que no puede ser borrada"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr "%s no es un archivo"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr "confirme el borrado de %s"
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr "Por favor seleccione los adjuntos que serán borrados."
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr "borrado"
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr "%s no está en el directorio fuente por lo que no puede ser renombrado"
+
+#: ../IkiWiki/Plugin/rename.pm:62
+msgid "no change to the file name was specified"
+msgstr "no se ha indicado cambio alguno en el nombre del archivo"
+
+#: ../IkiWiki/Plugin/rename.pm:68
+#, perl-format
+msgid "illegal name"
+msgstr "nombre no válido"
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "limpiando el índice de búsquedas de hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:73
+#, perl-format
+msgid "%s already exists"
+msgstr "%s ya existe"
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr "%s ya existe en el disco"
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, perl-format
+msgid "rename %s"
+msgstr "cambiando de nombre %s"
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "actualizando el índice de búsquedas de hyperstraier"
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr "También cambia de nombre las subpáginas y los adjuntos"
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
-msgstr "el complemento shortcut no funciona sin una página shortcuts.mdwn"
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr "Únicamente un adjunto puede ser renombrado a la vez."
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr "Por favor, seleccione el adjunto al que cambiar el nombre."
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr "%s cambia de nombre a %s"
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, perl-format
+msgid "update for rename of %s to %s"
+msgstr "actualizado el cambio de nombre de %s a %s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr "se necesita la instalación de Digest::SHA1 para indexar %s"
+
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr "buscar"
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr "el complemento shortcut no funcionará si no existe la página %s"
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr "shortcut necesita el parámetro 'name' ó el parámetro 'url'"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "El atajo %s apunta a <i>%s</i>"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
msgstr "Algunos emoticonos tienen errores"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
msgstr "error de análisis "
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+#, fuzzy
+msgid "invalid featurepoint diameter"
msgstr "diámetro inválido "
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+#, fuzzy
+msgid "invalid featurepoint location"
msgstr "localización errónea "
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "faltan valores"
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+#, fuzzy
+msgid "invalid height value"
msgstr "valor incorrecto para la altura"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
msgstr "falta el parámetro que indica el ancho"
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+#, fuzzy
+msgid "invalid width value"
msgstr "valor incorrecto para el ancho"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr "error fatal invocando el programa php"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "no puedo encontrar el archivo"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "formato de datos desconocido"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr "sin datos"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "Enlace directo para descarga"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
msgstr "error de análisis en la línea %d: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
msgstr "falta el parámetro \"id\""
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "no he encontrado la plantilla %s"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
msgstr "se ha producido un error fatal mientras procesaba la plantilla:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr "falta el código tex"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr "el código incluye órdenes latex anuladas"
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
msgid "failed to generate image from code"
msgstr "no he podido crear la imagen desde el código"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
-msgstr "(no se puede cambiar en el modo de previsualización)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
+msgstr "complemento"
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "la funcionalidad getctime no está incluida"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr "¿ activar %s ?"
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr "El archivo de configuración para este wiki es desconocido"
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr "principal"
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr "complementos"
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+"Los cambios en la configuración que se muestran más abajo precisan una "
+"reconstrucción del wiki para tener efecto."
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+"Para que los cambios en la configuración mostrados más abajo tengan efecto, "
+"es posible que necesite reconstruir el wiki."
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+"Error: el programa %s finaliza con un código mayor que cero (%s). Descarto "
+"los cambios en la configuración."
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr "no puedo determinar el identificador de un usuario no fiable como %s"
+
+#: ../IkiWiki/Receive.pm:85
+#, perl-format
+msgid "bad file name %s"
+msgstr "el nombre de archivo %s es erróneo"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+"encontrado un enlace simbólico en la ruta del directorio fuente (%s) -- use "
+"la directiva allow_symlinks_before_srcdir para permitir la acción"
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "ignorando el archivo %s porque su nombre no es correcto"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr "%s tiene mútiples páginas fuente posibles"
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "eliminando la antigua página %s"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "explorando %s"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "convirtiendo %s"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "convirtiendo la página %s, la cual referencia a %s"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "convirtiendo la página %s, la cual depende de %s"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr ""
"convirtiendo la página %s para actualizar la lista de páginas que hacen "
"referencia a ella."
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "eliminando la página %s puesto que ya no se deriva de %s"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
-msgstr "ikwiki: no puedo convertir la página %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
+msgstr "ikiwiki: no puedo convertir la página %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "no puedo leer el archivo %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "generando programas auxiliares.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr "debe escribir un nombre wiki (que contiene caracteres alfanuméricos)"
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "reconstruyendo el wiki.."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr "el sistema de control de versiones %s no está soportado"
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "actualizando el wiki.."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr "no he podido crear un repositorio con el programa ikiwiki-makerepo"
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "completado"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
+"** Desactivando el complemento %s dado que está fallando con este mensaje:"
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "el programa envoltorio no ha sido especificado"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "no puedo escribir en %s: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "ha fallado la compilación del programa %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "creado con éxito el programa envoltorio %s"
msgid "usage: ikiwiki [options] source dest"
msgstr "uso: ikiwiki [opciones] origen destino"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr " ikiwiki --setup archivo_de_configuración"
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr "uso: --set variable=valor"
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "generando programas auxiliares.."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "reconstruyendo el wiki.."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "actualizando el wiki.."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Comentarios"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
"Es obligatorio especificar un url al wiki con el parámetro --url si se "
"utiliza el parámetro --cgi"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "Error"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr "no puedo emplear varios complementos rcs"
+
+#: ../IkiWiki.pm:569
+#, perl-format
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr "no he podido cargar el complemento externo %s necesario para %s"
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:1243
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "preprocessing loop detected on %s at depth %i"
msgstr ""
-"se ha detectado un bucle de preprocesado %s en la página %s en la vuelta "
+"se ha detectado en la página %s un bucle de preprocesado en la iteración "
"número %i"
-#~ msgid ""
-#~ "REV is not set, not running from mtn post-commit hook, cannot send "
-#~ "notifications"
-#~ msgstr ""
-#~ "La variable de entorno REV no está definida, por lo que no puede "
-#~ "funcionar svn post-commit desde monotone; no puedo enviar ninguna "
-#~ "notificación"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr "si"
-#~ msgid "REV is not a valid revision identifier, cannot send notifications"
-#~ msgstr ""
-#~ "REV no es un identificador de revisión válido, por lo que no puedo enviar "
-#~ "ninguna notificación"
+#: ../IkiWiki.pm:1915
+#, perl-format
+msgid "cannot match pages: %s"
+msgstr "no encuentro páginas coincidentes: %s"
-#~ msgid ""
-#~ "REV is not set, not running from svn post-commit hook, cannot send "
-#~ "notifications"
-#~ msgstr ""
-#~ "La variable de entorno REV no está definida, por lo que no puede "
-#~ "funcionar svn post-commit; no puedo enviar ninguna notificación"
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr "¿ Qué nombre tendrá el wiki ?"
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr "wiki"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "actualizado el wiki %s y la página %s por el usuario %s"
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr "¿ Qué sistema de control de versiones empleará ?"
-#~ msgid "link is no longer supported"
-#~ msgstr "el metadato link ya no puede usarse"
+#: ../auto.setup:20
+#, fuzzy
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+"¿ Qué usuario del wiki (ó qué identificador openid) será el empleado como "
+"administrador ? "
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr "¿ Cuál es el dominio para el servidor web ?"
-#~ msgid "%s not found"
-#~ msgstr "no he encontrado la plantilla %s "
+#, fuzzy
+#~ msgid "discussion"
+#~ msgstr "Comentarios"
-#~ msgid "What's this?"
-#~ msgstr "¿ Qué es esto ?"
+#~ msgid "rendering %s"
+#~ msgstr "convirtiendo %s"
+
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr ""
+#~ "Es obligatorio indicar %s cuando se utiliza el complemento de búsqueda de "
+#~ "google"
-#~ msgid "(use FirstnameLastName)"
-#~ msgstr "(utilice la forma NombreApellidos)"
+#~ msgid "bad size \"%s\""
+#~ msgstr "tamaño erróneo \"%s\""
# Cyril Brulebois <cyril.brulebois@enst-bretagne.fr>, 2007.
msgid ""
msgstr ""
-"Project-Id-Version: \n"
+"Project-Id-Version: ikiwiki 3.141\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-04-16 18:36-0400\n"
-"PO-Revision-Date: 2008-04-29 17:46+0200\n"
-"Last-Translator: Christian Perrier <bubulle@debian.org>\n"
+"POT-Creation-Date: 2009-08-25 18:43-0400\n"
+"PO-Revision-Date: 2009-08-17 10:06+0200\n"
+"Last-Translator: Philippe Batailler <philippe.batailler@free.fr>\n"
"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: KBabel 1.11.4\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Vous devez d'abord vous identifier."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+"Erreur de configuration probable : sslcookie est positionné mais vous tentez "
+"de vous connecter avec http au lieu de https"
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
-msgstr "Échec de l'identification, vous devriez peut-être autoriser les cookies."
+msgstr "Échec de l'identification, vous devez autoriser les cookies."
-#: ../IkiWiki/CGI.pm:173 ../IkiWiki/CGI.pm:499
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
msgid "Your login session has expired."
msgstr "Session d'authentification expirée."
-#: ../IkiWiki/CGI.pm:194
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr "S’identifier"
-#: ../IkiWiki/CGI.pm:195
+#: ../IkiWiki/CGI.pm:190
msgid "Preferences"
msgstr "Préférences"
-#: ../IkiWiki/CGI.pm:196
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr "Administrateur"
-#: ../IkiWiki/CGI.pm:248
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Les préférences ont été enregistrées."
-#: ../IkiWiki/CGI.pm:306
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "%s n'est pas une page éditable"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Vous avez été banni."
-#: ../IkiWiki/CGI.pm:410 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:265 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:172
-msgid "discussion"
-msgstr "Discussion"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1269
+msgid "Error"
+msgstr "Erreur"
-#: ../IkiWiki/CGI.pm:466
-#, perl-format
-msgid "creating %s"
-msgstr "Création de %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr "Agrégation déclenchée par le web"
-#: ../IkiWiki/CGI.pm:484 ../IkiWiki/CGI.pm:512 ../IkiWiki/CGI.pm:522
-#: ../IkiWiki/CGI.pm:556 ../IkiWiki/CGI.pm:601
-#, perl-format
-msgid "editing %s"
-msgstr "Édition de %s"
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr "Rien à faire pour le moment, tous les flux sont à jour !"
-#: ../IkiWiki/CGI.pm:691
-msgid "You are banned."
-msgstr "Vous avez été banni."
-
-#: ../IkiWiki/Plugin/aggregate.pm:101
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr "Paramètre %s manquant"
-#: ../IkiWiki/Plugin/aggregate.pm:128
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "Nouveau flux"
-#: ../IkiWiki/Plugin/aggregate.pm:142
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "Articles"
-#: ../IkiWiki/Plugin/aggregate.pm:144
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "Nouveau"
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "Fin de validité de %s (date de %s jours)"
-#: ../IkiWiki/Plugin/aggregate.pm:314
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "Fin de validité de %s"
-#: ../IkiWiki/Plugin/aggregate.pm:341
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "A été correctement traité à %s"
+msgid "last checked %s"
+msgstr "dernière vérification : %s"
-#: ../IkiWiki/Plugin/aggregate.pm:345
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "Vérification du flux %s..."
-#: ../IkiWiki/Plugin/aggregate.pm:350
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "Impossible de trouver de flux à %s"
-#: ../IkiWiki/Plugin/aggregate.pm:365
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
msgstr "Flux introuvable "
-#: ../IkiWiki/Plugin/aggregate.pm:376
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr "(chaîne UTF-8 non valable supprimée du flux)"
-#: ../IkiWiki/Plugin/aggregate.pm:382
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr "(échappement des entités de flux)"
-#: ../IkiWiki/Plugin/aggregate.pm:388
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "Plantage du flux XML::Feed !"
-#: ../IkiWiki/Plugin/aggregate.pm:462
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "Création de la nouvelle page %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr "Suppression du compartiment S3 (« bucket »)..."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "Terminé"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr "Vous devez spécifier %s"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+msgid "Failed to create S3 bucket: "
+msgstr "Impossible de créer un compartiment S3 :"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+msgid "Failed to save file to S3: "
+msgstr "Impossible de sauvegarder le fichier dans le compartiment S3 :"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+msgid "Failed to delete file from S3: "
+msgstr "Échec lors de la suppression du fichier sur S3 :"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr "Il existe déjà une page nommée %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr "Action interdite par allowed_attachments"
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr "Nom de la pièce jointe incorrect"
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr "Envoi de la pièce jointe"
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr "Génération de l'index automatique"
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+"Désolé, mais cela ressemble à un « spam » selon les critères de <a href="
+"\"http://blogspam.net/\">blogspam</a> : "
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr "%s sur %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
-msgstr "Il n'existe pas de lien cassé !"
+msgstr "Aucun lien cassé !"
+
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr "Format de page non reconnu %s"
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr "Un commentaire doit avoir un contenu."
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr "Anonyme"
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr "Nom de page incorrect"
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, perl-format
+msgid "commenting on %s"
+msgstr "Faire un commentaire sur %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr "La page '%s' n'existe pas, commentaire impossible."
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr "Le commentaire pour la page '%s' est terminé."
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr "Le commentaire a été enregistré, en attente de « modération »"
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr "Votre commentaire sera publié après vérification par le modérateur"
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr "Commentaire ajouté"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr "Commentaire ajouté : %s"
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr "Vous n'êtes pas authentifié comme administrateur"
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr "Modération du commentaire"
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr "modération du commentaire"
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr "Commentaires"
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
-msgstr "le paramètre %s est obligatoire"
+msgstr "Le paramètre %s est obligatoire"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr "Aucun texte n'a été copié dans cette page"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr "Aucun texte n'a été copié dans cette page avec l'identifiant %s"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, perl-format
+msgid "removing old preview %s"
+msgstr "Suppression de l'ancienne prévisualisation %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "%s n'est pas une page éditable"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "Création de %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "Édition de %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
msgid "template not specified"
msgstr "modèle (« template ») non indiqué"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
msgid "match not specified"
msgstr "correspondance non indiquée"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr "edittemplate %s enregistré pour %s"
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
msgid "failed to process"
msgstr "Échec du traitement"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr "le format et le texte doivent être indiqués"
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "Échec du lancement de « fortune »"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
-msgstr "Échec dans la recherche d'une URL dans le Code HTML"
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+msgid "missing page"
+msgstr "Page manquante"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr "La page %s n'existe pas."
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+msgid "not a page"
+msgstr "Ce n'est pas une page."
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "%s est une pièce jointe, pas une page."
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr "Vous n'êtes pas autorisé à modifier %s"
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr "Vous ne pouvez pas modifier un fichier dont le mode est %s"
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr "Vous n'êtes pas autorisé à modifier le mode des fichiers"
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Vous devez indiquer %s lors de l'utilisation du greffon %s."
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr "Impossible d'analyser l'URL, pas de nom de domaine"
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
msgstr "Échec du lancement de graphviz"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "Ce programme n'est pas un programme graphviz valable"
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
#, perl-format
-msgid "bad size \"%s\""
-msgstr "taille incorrecte « %s »"
+msgid "tohighlight contains unknown file type '%s'"
+msgstr "tohighlight contient un type de fichier inconnu : '%s'"
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr "Code source : %s"
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+"Avertissement : le module perl « highlight » n'est pas disponible. "
+"Continuation malgré tout."
+
+#: ../IkiWiki/Plugin/img.pm:63
+msgid "Image::Magick is not installed"
+msgstr "Image::Magick n'est pas installé"
+
+#: ../IkiWiki/Plugin/img.pm:72
+#, perl-format
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr "Format de la taille incorrect \"%s\", (devrait être LxH)"
+
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr "Échec de la lecture de %s : %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
msgstr "Échec du redimensionnement : %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, perl-format
msgid "failed to determine size of image %s"
msgstr "Échec de la détermination de la taille de l'image : %s"
-#: ../IkiWiki/Plugin/inline.pm:46
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
"Vous devez indiquer l'URL du wiki par --url lors de l'utilisation de --rss "
"ou --atom"
-#: ../IkiWiki/Plugin/inline.pm:153
+#: ../IkiWiki/Plugin/inline.pm:138
+msgid "page editing not allowed"
+msgstr "Modification de page interdite"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+msgid "missing pages parameter"
+msgstr "Paramètre « pages » manquant"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr "Les paramètres %s et %s ne peuvent être utilisés ensemble."
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr "Sort::Naturally est nécessaire pour un tri « title_natural »"
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "Type de tri %s inconnu"
-#: ../IkiWiki/Plugin/inline.pm:224
+#: ../IkiWiki/Plugin/inline.pm:329
msgid "Add a new post titled:"
msgstr "Ajouter un nouvel article dont le titre est :"
-#: ../IkiWiki/Plugin/inline.pm:240
+#: ../IkiWiki/Plugin/inline.pm:349
#, perl-format
msgid "nonexistant template %s"
-msgstr "Le modèle (« template ») %s n'existe pas"
+msgstr "Le modèle de page %s n'existe pas"
-#: ../IkiWiki/Plugin/inline.pm:273 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Discussion"
-
-#: ../IkiWiki/Plugin/inline.pm:500
+#: ../IkiWiki/Plugin/inline.pm:614
msgid "RPC::XML::Client not found, not pinging"
msgstr "RPC::XML::Client introuvable, pas de réponse au ping"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr "Échec du lancement de dot"
-#: ../IkiWiki/Plugin/lockedit.pm:29
+#: ../IkiWiki/Plugin/lockedit.pm:47
#, perl-format
-msgid "%s is locked by %s and cannot be edited"
-msgstr "%s est verrouillé par %s et ne peut être édité"
+msgid "%s is locked and cannot be edited"
+msgstr "%s est verrouillé et ne peut être modifié"
+
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr "mulitmarkdown est activé mais Text::Multimarkdown n'est pas installé"
-#: ../IkiWiki/Plugin/mdwn.pm:42
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"Échec du chargement du module Perl Markdown.pm (%s) ou de /usr/bin/markdown "
"(%s)"
-#: ../IkiWiki/Plugin/meta.pm:132
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr "Feuille de style introuvable "
-#: ../IkiWiki/Plugin/meta.pm:166
+#: ../IkiWiki/Plugin/meta.pm:196
msgid "redir page not found"
-msgstr "Page de redirection introuvable "
+msgstr "Page de redirection introuvable"
-#: ../IkiWiki/Plugin/meta.pm:179
+#: ../IkiWiki/Plugin/meta.pm:210
msgid "redir cycle is not allowed"
msgstr "Redirection cyclique non autorisée"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Miroirs"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Miroir"
msgid "more"
msgstr "lire la suite"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime n'est pas implémenté"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr "S'identifier en tant que"
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Obtenir un compte OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+msgid "All pages have other pages linking to them."
msgstr "Toutes les pages sont liées à d'autres pages."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
-msgstr "Modèle incorrect ou manquant"
+msgstr "Modèle de page incorrect ou manquant"
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Le compte a été créé. Vous pouvez maintenant vous identifier."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Erreur lors de la création du compte."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+"Aucune adresse indiquée. Impossible d'envoyer les instructions pour "
+"réinitialiser le mot de passe."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
-msgstr "Échec de l'envoi du courriel"
+msgstr "Impossible d'envoyer un courriel"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+"Vous avez reçu un message contenant les instructions pour réinitialiser le "
+"mot de passe"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr "Adresse pour la réinitialisation du mot de passe incorrecte"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr "réinitialisation du mot de passe refusée"
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr "Ping reçu"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Votre mot de passe vous a été envoyé par courriel."
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr "les paramètres « from » et « to » sont nécessaires."
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, perl-format
+msgid "Will ping %s"
+msgstr "va envoyer un ping à %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr "Les instructions du wiki %s sont ignorées (ce wiki est %s)"
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+msgid "LWP not found, not pinging"
+msgstr "LWP est introuvable. Pas de réponse au ping"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+"Note : ancienne version de po4a détectée. Il est recommandé d'installer la "
+"version 0.35."
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s n'est pas un code de langue valable"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+"%s n'est pas une valeur correcte pour po_link_to, retour à la valeur par "
+"défaut."
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+"po_link_to=negotiated nécessite que usedirs soit activé, retour à "
+"po_link_to=default."
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+"Reconstruction de toutes les pages pour corriger les titres (greffon "
+"« meta »)."
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, perl-format
+msgid "building %s"
+msgstr "construction de %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr "Fichiers PO mis à jour."
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+"Impossible de supprimer cette traduction. Si la page maître est supprimée, "
+"alors ses traductions seront supprimées."
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+"Impossible de renommer cette traduction. Si la page maître est renommée, "
+"alors ses traductions pourront être renommées."
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr "Le fichier POT %s n'existe pas."
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "Impossible de copier le fichier PO underlay dans %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, perl-format
+msgid "failed to update %s"
+msgstr "Impossible de mettre à jour %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "Impossible de copier le fichier POT dans %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr "N/A"
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, perl-format
+msgid "failed to translate %s"
+msgstr "Impossible de traduire %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr "Fichiers PO obsolètes supprimés."
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, perl-format
+msgid "failed to write %s"
+msgstr "Impossible de modifier %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+msgid "failed to translate"
+msgstr "Impossible de traduire"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, perl-format
+msgid "failed to read %s"
+msgstr "Impossible de lire %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+"Données gettext incorrectes, retour à la page précédente pour la poursuite "
+"des modifications."
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "Voter"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Total des suffrages :"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "polygen n'est pas installé"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "Échec du lancement de polygen"
+#: ../IkiWiki/Plugin/polygen.pm:60
+msgid "command failed"
+msgstr "Échec de la commande"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "formule manquante"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "formule inconnue"
#: ../IkiWiki/Plugin/prettydate.pm:32
msgid "late %A afternoon"
-msgstr "tard l'après-midi de %A"
+msgstr "tard dans l'après-midi de %A"
#: ../IkiWiki/Plugin/prettydate.pm:33
msgid "%A evening"
-msgstr "%A soir"
+msgstr "%A en soirée"
#: ../IkiWiki/Plugin/prettydate.pm:35
msgid "late %A evening"
-msgstr "tard %A soir"
+msgstr "tard %A en soirée"
#: ../IkiWiki/Plugin/prettydate.pm:37
msgid "%A night"
msgstr "%A, durant la nuit"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "%A, à l'heure du thé"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "à minuit"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "%A, à midi"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
-msgid "missing page"
-msgstr "Page manquante"
-
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/progress.pm:34
#, perl-format
-msgid "The page %s does not exist."
-msgstr "La page %s n'existe pas."
+msgid "illegal percent value %s"
+msgstr "pourcentage %s illégal"
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+"L'un des paramètres « percent », « totalpages » ou « donepages » est nécessaire."
-#: ../IkiWiki/Plugin/recentchangesdiff.pm:26
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
msgid "(Diff truncated)"
msgstr "(fichier de différences tronqué)"
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr "%s n'existe pas"
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s n'est pas dans srcdir et ne peut donc pas être supprimé"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr "%s n'est pas un fichier"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr "Suppression de %s confirmée"
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr "Veuillez choisir la pièce jointe à supprimer"
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr "supprimé"
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr "%s n'est pas dans srcdir. Impossible de le renommer"
+
+#: ../IkiWiki/Plugin/rename.pm:62
+msgid "no change to the file name was specified"
+msgstr "Aucun changement dans le nom du fichier n'a été spécifié"
+
+#: ../IkiWiki/Plugin/rename.pm:68
+#, perl-format
+msgid "illegal name"
+msgstr "Appellation interdite"
+
+#: ../IkiWiki/Plugin/rename.pm:73
+#, perl-format
+msgid "%s already exists"
+msgstr "%s existe déjà"
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr "%s existe déjà sur le disque"
+
+#: ../IkiWiki/Plugin/rename.pm:122
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Vous devez indiquer %s lors de l'utilisation du greffon de recherche"
+msgid "rename %s"
+msgstr "%s renommé"
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "Nettoyage de l'index de recherche de hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr "« SubPages » et attachements renommés."
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "Mise à jour de l'index de recherche de hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr "Modification de pièce jointe : une seule à la fois"
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
-msgstr "Le greffon de raccourci (« shortcut ») ne fonctionnera pas sans shortcuts.mdwn"
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr "Veuillez sélectionner la pièce jointe à renommer"
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr "Renomme %s en %s"
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, perl-format
+msgid "update for rename of %s to %s"
+msgstr "mise à jour, suite au changement de %s en %s"
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr "Digest::SHA1 est nécessaire pour indexer %s"
+
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr "recherche"
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr "Le greffon « shortcut » ne fonctionnera pas sans %s"
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr "Il manque le paramètre nom ou URL."
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "Le raccourci %s pointe vers <i>%s</i>"
-#: ../IkiWiki/Plugin/smiley.pm:32
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
msgstr "Aucun smiley n'a pu être analysé"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
msgstr "Erreur d'analyse"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
msgstr "Diamètre du point incorrect"
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
msgstr "Emplacement du point incorrect"
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "Il manque des valeurs"
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+msgid "invalid height value"
msgstr "Hauteur incorrecte"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
-msgstr "Le paramètre de largeur manque dans le modèle (« template »)"
+msgstr "Le paramètre largeur manque"
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+msgid "invalid width value"
msgstr "Largeur incorrecte"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr "Échec du lancement de php"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "Fichier introuvable"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "Format de données inconnu"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
-msgstr "Données vides"
+msgstr "Pas de données"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "Téléchargement direct des données"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
msgstr "Erreur d'analyse à la ligne %d : %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
msgstr "Paramètre d'identification manquant"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
-msgstr "Modèle (« template ») %s introuvable "
+msgstr "Modèle de page %s introuvable"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
msgstr "Échec du traitement :"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr "Il manque le code TeX"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr "Le code comporte des commandes LaTeX non permises"
-#: ../IkiWiki/Plugin/teximg.pm:88
+#: ../IkiWiki/Plugin/teximg.pm:128
msgid "failed to generate image from code"
msgstr "Échec de la création de l'image à partir du code"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
-msgstr "(non permutable en mode prévisualisation)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
+msgstr "greffon"
-#: ../IkiWiki/Rcs/Stub.pm:69
-msgid "getctime not implemented"
-msgstr "getctime n'est pas implémenté"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr "activer %s ?"
-#: ../IkiWiki/Render.pm:289 ../IkiWiki/Render.pm:310
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr "Le fichier de configuration de ce wiki n'est pas connu"
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr "Partie principale"
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr "Greffons"
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+"Les changements de configuration ci-dessous nécessitent une recompilation du "
+"wiki pour prendre effet"
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+"Pour que les changements de configuration ci-dessous prennent effet vous "
+"devez recompiler le wiki"
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr "Erreur : %s s'est terminé anormalement (%s). Modifications ignorées."
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+"Impossible de déterminer l'identifiant de %s, (enregistrement non fiable)"
+
+#: ../IkiWiki/Receive.pm:85
+#, perl-format
+msgid "bad file name %s"
+msgstr "Nom de fichier incorrect %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+"Lien symbolique trouvé dans l'adresse de srcdir (%s) -- pour l'autoriser, "
+"activez le paramètre « allow_symlinks_before_srcdir »."
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "Omission du fichier au nom incorrect %s"
-#: ../IkiWiki/Render.pm:365
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr "%s peut être associé à plusieurs pages source."
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "Suppression de l'ancienne page %s"
-#: ../IkiWiki/Render.pm:406
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
-msgstr "Parcours de %s"
+msgstr "Examen de %s"
-#: ../IkiWiki/Render.pm:411
+#: ../IkiWiki/Render.pm:447
#, perl-format
-msgid "rendering %s"
-msgstr "Affichage de %s"
+msgid "building %s, which links to %s"
+msgstr "Reconstruction de %s, qui est lié à %s"
-#: ../IkiWiki/Render.pm:432
+#: ../IkiWiki/Render.pm:473
#, perl-format
-msgid "rendering %s, which links to %s"
-msgstr "Affichage de %s, qui est lié à %s"
+msgid "building %s, which depends on %s"
+msgstr "Reconstruction de %s, qui dépend de %s"
-#: ../IkiWiki/Render.pm:453
+#: ../IkiWiki/Render.pm:513
#, perl-format
-msgid "rendering %s, which depends on %s"
-msgstr "Affichage de %s, qui dépend de %s"
+msgid "building %s, to update its backlinks"
+msgstr "Reconstruction de %s, afin de mettre à jour ses rétroliens"
-#: ../IkiWiki/Render.pm:492
+#: ../IkiWiki/Render.pm:525
#, perl-format
-msgid "rendering %s, to update its backlinks"
-msgstr "Affichage de %s, afin de mettre à jour ses rétroliens"
+msgid "removing %s, no longer built by %s"
+msgstr "Suppression de %s, qui n'est plus rendu par %s"
-#: ../IkiWiki/Render.pm:504
+#: ../IkiWiki/Render.pm:549
#, perl-format
-msgid "removing %s, no longer rendered by %s"
-msgstr "Suppression de %s, qui n'est plus affiché par %s"
-
-#: ../IkiWiki/Render.pm:530
-#, perl-format
-msgid "ikiwiki: cannot render %s"
-msgstr "ikiwiki : impossible d'afficher %s"
+msgid "ikiwiki: cannot build %s"
+msgstr "ikiwiki : impossible de reconstruire %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "Lecture impossible de %s : %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "Création des fichiers CGI..."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
+"Vous devez spécifier un nom de wiki (contenant des caractères "
+"alphanumériques)"
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "Reconstruction du wiki..."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr "Système de contrôle de version non reconnu : %s"
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "Rafraîchissement du wiki..."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr "Échec lors de la création du dépôt avec ikiwiki-makerepo"
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "Terminé"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
+"** Désactivation du greffon %s, l'installation a échoué avec le message "
+"suivant :"
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
#: ../IkiWiki/Wrapper.pm:20
msgid "cannot create a wrapper that uses a setup file"
-msgstr "Impossible de créer un fichier CGI utilisant un fichier de configuration"
+msgstr ""
+"Impossible de créer un fichier CGI utilisant un fichier de configuration"
#: ../IkiWiki/Wrapper.pm:24
msgid "wrapper filename not specified"
-msgstr "Le nom de fichier de l'enrobage n'a pas été indiqué"
-
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "Échec de l'écriture de %s : %s"
+msgstr "Le nom du fichier CGI n'a pas été indiqué"
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "Échec de la compilation de %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "%s a été créé avec succès"
msgid "usage: ikiwiki [options] source dest"
msgstr "Syntaxe : ikiwiki [options] source destination"
-#: ../ikiwiki.in:82
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr " ikiwiki --setup fichier de configuration"
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr "Syntaxe : -- set var=valeur"
-#: ../IkiWiki.pm:117
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "Création des fichiers CGI..."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "Reconstruction du wiki..."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "Rafraîchissement du wiki..."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Discussion"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
-"Vous devez indiquer une URL vers le wiki par --url lors de l'utilisation de "
-"--cgi"
+"Vous devez indiquer l'URL du wiki par --url lors de l'utilisation de --cgi"
-#: ../IkiWiki.pm:186 ../IkiWiki.pm:187
-msgid "Error"
-msgstr "Erreur"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr "Impossible d'utiliser plusieurs systèmes de contrôle des versions"
+
+#: ../IkiWiki.pm:569
+#, perl-format
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr "Impossible de charger le greffon externe nécessaire au greffon %s : %s"
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:1251
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
-msgstr "%s une boucle a été détectée dans le prétraitement de %s, à la profondeur %i"
+msgid "preprocessing loop detected on %s at depth %i"
+msgstr "Une boucle de prétraitement a été détectée sur %s à hauteur de %i"
+
+#: ../IkiWiki.pm:1791
+msgid "yes"
+msgstr "oui"
+
+#: ../IkiWiki.pm:1915
+#, perl-format
+msgid "cannot match pages: %s"
+msgstr "Impossible de trouver les pages %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr "Nom du wiki :"
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr "wiki"
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr "Système de contrôle de version utilisé :"
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr "Identifiant de l'administrateur (utilisateur du wiki ou openid) :"
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr "Nom de domaine du serveur HTTP :"
+
+#~ msgid "discussion"
+#~ msgstr "Discussion"
+
+#~ msgid "rendering %s"
+#~ msgstr "Reconstruction de %s"
+
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr "Vous devez indiquer %s lors de l'utilisation du greffon « google »."
+
+#~ msgid "bad size \"%s\""
+#~ msgstr "taille incorrecte « %s »"
+#~ msgid "<p class=\"error\">Error: %s exited nonzero (%s)"
+#~ msgstr ""
+#~ "<p class=\"erreur\">Erreur : %s s'est terminé, valeur de sortie nonzero (%"
+#~ "s)"
msgstr ""
"Project-Id-Version: ikiwiki-gu\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
"PO-Revision-Date: 2007-01-11 16:05+0530\n"
"Last-Translator: Kartik Mistry <kartik.mistry@gmail.com>\n"
"Language-Team: Gujarati <team@utkarsh.org>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "તમારે પ્રથમ લોગ ઇન થવું પડશે."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr "પ્રવેશ નિષ્ફળ, કદાચ તમારી કુકીઓ સક્રિય બનાવવી પડશે?"
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr ""
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
#, fuzzy
msgid "Preferences"
msgstr "પ્રાથમિકતાઓ સંગ્રહાઇ."
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr ""
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "પ્રાથમિકતાઓ સંગ્રહાઇ."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "%s એ સુધારી શકાય તેવું પાનું નથી"
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "ચર્ચા"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "તમારા પર પ્રતિબંધ છે."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "%s બનાવે છે"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "ક્ષતિ"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "%s સુધારે છે"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr ""
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "તમારા પર પ્રતિબંધ છે."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr "ખોવાયેલ %s વિકલ્પ"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "નવું ફીડ"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "પોસ્ટ"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "નવું"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "જુનું કરે છે %s (%s દિવસો જુનું)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "જુનું કરે છે %s"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "આના પર બરાબર છે %s"
+msgid "last checked %s"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "ફીડ %s ચકાસે છે ..."
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "%s પર ફીડ મળી શક્યું નહી"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
msgstr "ફીડ મળ્યું નહી"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, fuzzy, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr "ફીડમાંથી અયોગ્ય રીતે UTF-8 નીકાળેલ છે"
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "ફીડ ભાંગી ગયું XML::Feed!"
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "નવું પાનું %s બનાવે છે"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "સંપૂર્ણ"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "મેઇલ મોકલવામાં નિષ્ફળ"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "મેઇલ મોકલવામાં નિષ્ફળ"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "માપ બદલવામાં નિષ્ફળ: %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr ""
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "અહીં કોઇ તૂટેલ કડી નથી!"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, fuzzy, perl-format
+msgid "commenting on %s"
+msgstr "%s બનાવે છે"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, fuzzy, perl-format
msgid "%s parameter is required"
msgstr "\"test\" અને \"then\" વિકલ્પો જરૂરી છે"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, fuzzy, perl-format
+msgid "removing old preview %s"
+msgstr "જુનાં પાનાં દૂર કરે છે %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "%s એ સુધારી શકાય તેવું પાનું નથી"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "%s બનાવે છે"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "%s સુધારે છે"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
#, fuzzy
msgid "template not specified"
msgstr "ટેમ્પલેટ %s મળ્યું નહી"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
#, fuzzy
msgid "match not specified"
msgstr "આવરણ ફાઇલનામ સ્પષ્ટ કરેલ નથી"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
#, fuzzy
msgid "failed to process"
msgstr "ક્રિયા કરવામાં નિષ્ફળ:"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "ભવિષ્ય નિષ્ફળ"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
-msgstr "htmlમાં યુઆરએલ શોધવામાં નિષ્ફળ"
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+#, fuzzy
+msgid "missing page"
+msgstr "ખોવાયેલ કિંમતો"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+#, fuzzy
+msgid "not a page"
+msgstr "વાંચી શકાતી નથી %s: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, fuzzy, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "%s એ સુધારી શકાય તેવું પાનું નથી"
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "જ્યારે શોધ પ્લગઇન ઉપયોગ કરતા હોવ ત્યારે %s સ્પષ્ટ કરવું જ પડશે"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
msgstr "ગ્રાફવિઝ ચલાવવામાં નિષ્ફળ"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "કાર્યક્રમએ યોગ્ય ગ્રાફવિઝ કાર્યક્રમ નથી"
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+#, fuzzy
+msgid "Image::Magick is not installed"
+msgstr "પોલિગોન સ્થાપિત નથી"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
-msgstr "અયોગ્ય માપ \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr ""
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr "%s વાંચવામાં નિષ્ફળ: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
msgstr "માપ બદલવામાં નિષ્ફળ: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, fuzzy, perl-format
msgid "failed to determine size of image %s"
msgstr "માપ બદલવામાં નિષ્ફળ: %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr "--rss અથવા --atom ઉપયોગ કરતી વખતે વીકીમાં --url ઉપયોગ કરવું જ પડશે"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+#, fuzzy
+msgid "page editing not allowed"
+msgstr "ફીડ મળ્યું નહી"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+#, fuzzy
+msgid "missing pages parameter"
+msgstr "ખોવાયેલ %s વિકલ્પ"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "અજાણ્યો ગોઠવણી પ્રકાર %s"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr "આ શિર્ષકથી નવું પોસ્ટ ઉમેરો:"
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr "અસ્તિત્વમાં ન હોય તેવું ટેમ્પલેટ %s"
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "ચર્ચા"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "RPC::XML::Client મળ્યું નહી, પિંગ કરવામાં આવતું નથી"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr "ડોટ ચલાવવામાં નિષ્ફળ"
-#: ../IkiWiki/Plugin/lockedit.pm:29
-#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, fuzzy, perl-format
+msgid "%s is locked and cannot be edited"
msgstr "%s એ %s દ્વારા તાળું મરાયેલ છે અને તેમાં સુધારો કરી શકાશે નહી"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr "Markdown.pm પર્લ મોડ્યુલ (%s) અથવા /usr/bin/markdown (%s) લાવવામાં નિષ્ફળ"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr "સ્ટાઇલશીટ મળ્યું નહી"
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
#, fuzzy
msgid "redir page not found"
msgstr "ફીડ મળ્યું નહી"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
#, fuzzy
msgid "redir cycle is not allowed"
msgstr "ફીડ મળ્યું નહી"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "મિરરો"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "મિરર"
msgid "more"
msgstr "વધુ"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime અમલમાં મૂકાયેલ નથી"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "ઓપનઆઇડી મેળવો"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "બધા પાનાંઓ બીજા પાનાંઓ વડે જોડાયેલ છે."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "ખાતું બનાવવાનું સફળ. તમે હવે લોગઇન કરી શકો છો."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "ખાતું બનાવવામાં ક્ષતિ."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "મેઇલ મોકલવામાં નિષ્ફળ"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "તમારો પાસવર્ડ તમને ઇમેઇલ કરવામાં આવ્યો છે."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, fuzzy, perl-format
+msgid "Will ping %s"
+msgstr "%s સુધારે છે"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+#, fuzzy
+msgid "LWP not found, not pinging"
+msgstr "RPC::XML::Client મળ્યું નહી, પિંગ કરવામાં આવતું નથી"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, fuzzy, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s એ સુધારી શકાય તેવું પાનું નથી"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "%s સુધારે છે"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "%s કમ્પાઇલ કરવામાં નિષ્ફળ"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "%s કમ્પાઇલ કરવામાં નિષ્ફળ"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "%s કમ્પાઇલ કરવામાં નિષ્ફળ"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "માપ બદલવામાં નિષ્ફળ: %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "%s લખવામાં નિષ્ફળ: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "ડોટ ચલાવવામાં નિષ્ફળ"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "%s વાંચવામાં નિષ્ફળ: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "મત"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "કુલ મત:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "પોલિગોન સ્થાપિત નથી"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "પોલિગોન નિષ્ફળ"
+#: ../IkiWiki/Plugin/polygen.pm:60
+#, fuzzy
+msgid "command failed"
+msgstr "ભવિષ્ય નિષ્ફળ"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "ખોવાયેલ સૂત્ર"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "અજાણ્યું સૂત્ર"
msgid "%A night"
msgstr "%A રાત્રે"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "ચા ના સમયે %A પર"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "મધ્યરાત્રે"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "બપોરે %A પર"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, fuzzy, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s એ %s દ્વારા તાળું મરાયેલ છે અને તેમાં સુધારો કરી શકાશે નહી"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, fuzzy, perl-format
+msgid "%s is not a file"
+msgstr "%s એ સુધારી શકાય તેવું પાનું નથી"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
#, fuzzy
-msgid "missing page"
-msgstr "àª\96à«\8bવાયà«\87લ àª\95િàª\82મતà«\8b"
+msgid "no change to the file name was specified"
+msgstr "àª\86વરણ ફાàª\87લનામ સà«\8dપષà«\8dàª\9f àª\95રà«\87લ નથà«\80"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "The page %s does not exist."
+msgid "illegal name"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:73
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "જ્યારે શોધ પ્લગઇન ઉપયોગ કરતા હોવ ત્યારે %s સ્પષ્ટ કરવું જ પડશે"
+msgid "%s already exists"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, fuzzy, perl-format
+msgid "rename %s"
+msgstr "રેન્ડર કરે છે %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, fuzzy, perl-format
+msgid "update for rename of %s to %s"
+msgstr "%s નો સુધારો %s નાં %s વડે"
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "હાયપરસ્ટ્રેઇઝર શોધ અનુક્રમણિકા સાફ કરે છે"
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "હાયપરસ્ટ્રેઇઝર શોધ અનુક્રમણિકા સુધારે છે"
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr "ખોવાયેલ નામ અથવા યુઆરએલ વિકલ્પ"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "ટુંકોરસ્તો %s એ <i>%s</i> નો નિર્દેશ કરે છે"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
msgstr "કોઇપણ સ્માઇલીઓ ઉકેલવામાં નિષ્ફળ"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
msgstr "ઉકેલવામાં ક્ષતિ"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+#, fuzzy
+msgid "invalid featurepoint diameter"
msgstr "ખરાબ લાક્ષણિકબિંદુ વ્યાસ"
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+#, fuzzy
+msgid "invalid featurepoint location"
msgstr "ખરાબ લાક્ષણિકબિંદુ સ્થિતિ"
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "ખોવાયેલ કિંમતો"
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+#, fuzzy
+msgid "invalid height value"
msgstr "ખરાબ ઉંચાઇ કિંમત"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
msgstr "ખોવાયેલ પહોળાઇ વિકલ્પ"
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+#, fuzzy
+msgid "invalid width value"
msgstr "ખરાબ પહોળાઇ કિંમત"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr "php ચલાવવામાં નિષ્ફળ"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "ફાઇલ મળી શકી નહી"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "અજાણ્યો માહિતી પ્રકાર"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr "ખાલી માહિતી"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "સીધી માહિતી ડાઉનલોડ"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
msgstr "ઉકેલવાનું લીટી %d પર નિષ્ફળ: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
msgstr "ખોવાયેલ આઇડી વિકલ્પ"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "ટેમ્પલેટ %s મળ્યું નહી"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
msgstr "ક્રિયા કરવામાં નિષ્ફળ:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
#, fuzzy
msgid "missing tex code"
msgstr "ખોવાયેલ કિંમતો"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
#, fuzzy
msgid "failed to generate image from code"
msgstr "માપ બદલવામાં નિષ્ફળ: %s"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "getctime અમલમાં મૂકાયેલ નથી"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:85
+#, fuzzy, perl-format
+msgid "bad file name %s"
+msgstr "ખરાબ ફાઇલ નામ છોડી દે છે %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "ખરાબ ફાઇલ નામ છોડી દે છે %s"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "જુનાં પાનાં દૂર કરે છે %s"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "%s શોધે છે"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "રેન્ડર કરે છે %s"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "રેન્ડર કરે છે %s, જે %s સાથે જોડાણ ધરાવે છે"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "રેન્ડર કરે છે %s, જે %s પર આધારિત છે"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr "રેન્ડર કરે છે %s, તેનાં પાછળનાં જોડાણો સુધારવા માટે"
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "દૂર કરે છે %s, હવે %s વડે રેન્ડર કરાતું નથી"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: %s રેન્ડર કરી શકાતું નથી"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "વાંચી શકાતી નથી %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "આવરણ બનાવે છે.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "વીકી ફરીથી બનાવે છે.."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "વીકીને તાજી કરે છે.."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "સંપૂર્ણ"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "આવરણ ફાઇલનામ સ્પષ્ટ કરેલ નથી"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "%s લખવામાં નિષ્ફળ: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "%s કમ્પાઇલ કરવામાં નિષ્ફળ"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "સફળતાપૂર્વક પેદા કરેલ છે %s"
msgid "usage: ikiwiki [options] source dest"
msgstr "ઉપયોગ: ikiwiki [વિકલ્પો] source dest"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "આવરણ બનાવે છે.."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "વીકી ફરીથી બનાવે છે.."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "વીકીને તાજી કરે છે.."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "ચર્ચા"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr "જ્યારે --cgi ઉપયોગ કરતાં હોય ત્યારે વીકીનું યુઆરએલ સ્પષ્ટ કરવું જ પડશે"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "ક્ષતિ"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:569
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1243
+#, fuzzy, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr "%s પર શોધાયેલ લુપ %s પર ચલાવે છે %i ઉંડાણ પર"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
+#, fuzzy, perl-format
+msgid "cannot match pages: %s"
+msgstr "વાંચી શકાતી નથી %s: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr ""
+
+#~ msgid "discussion"
+#~ msgstr "ચર્ચા"
+
+#~ msgid "rendering %s"
+#~ msgstr "રેન્ડર કરે છે %s"
+
+#, fuzzy
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr "જ્યારે શોધ પ્લગઇન ઉપયોગ કરતા હોવ ત્યારે %s સ્પષ્ટ કરવું જ પડશે"
+
+#~ msgid "bad size \"%s\""
+#~ msgstr "અયોગ્ય માપ \"%s\""
+
+#~ msgid "failed to find url in html"
+#~ msgstr "htmlમાં યુઆરએલ શોધવામાં નિષ્ફળ"
+
+#~ msgid "processed ok at %s"
+#~ msgstr "આના પર બરાબર છે %s"
+
+#~ msgid "Your password has been emailed to you."
+#~ msgstr "તમારો પાસવર્ડ તમને ઇમેઇલ કરવામાં આવ્યો છે."
+
+#~ msgid "polygen failed"
+#~ msgstr "પોલિગોન નિષ્ફળ"
+
+#~ msgid "cleaning hyperestraier search index"
+#~ msgstr "હાયપરસ્ટ્રેઇઝર શોધ અનુક્રમણિકા સાફ કરે છે"
+
+#~ msgid "updating hyperestraier search index"
+#~ msgstr "હાયપરસ્ટ્રેઇઝર શોધ અનુક્રમણિકા સુધારે છે"
+
#, fuzzy
#~ msgid ""
#~ "REV is not set, not running from mtn post-commit hook, cannot send "
#~ msgstr ""
#~ "REV ગોઠવેલ નથી, svn post-commit hook માંથી ચાલતું નથી, નોંધ મોકલી શકાશે નહી"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "%s નો સુધારો %s નાં %s વડે"
-
#~ msgid "%s not found"
#~ msgstr "ટેમ્પલેટ %s મળ્યું નહી"
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-07-06 19:16-0400\n"
+"POT-Creation-Date: 2009-08-25 18:43-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"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../IkiWiki/CGI.pm:140
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr ""
-#: ../IkiWiki/CGI.pm:172
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
-#: ../IkiWiki/CGI.pm:190 ../IkiWiki/CGI.pm:525
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
msgid "Your login session has expired."
msgstr ""
-#: ../IkiWiki/CGI.pm:211
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr ""
-#: ../IkiWiki/CGI.pm:212
+#: ../IkiWiki/CGI.pm:190
msgid "Preferences"
msgstr ""
-#: ../IkiWiki/CGI.pm:213
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr ""
-#: ../IkiWiki/CGI.pm:267
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr ""
-#: ../IkiWiki/CGI.pm:325
-#, perl-format
-msgid "%s is not an editable page"
-msgstr ""
-
-#: ../IkiWiki/CGI.pm:436 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:266 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:162
-msgid "discussion"
-msgstr ""
-
-#: ../IkiWiki/CGI.pm:492
-#, perl-format
-msgid "creating %s"
-msgstr ""
-
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:538 ../IkiWiki/CGI.pm:548
-#: ../IkiWiki/CGI.pm:582 ../IkiWiki/CGI.pm:627
-#, perl-format
-msgid "editing %s"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
msgstr ""
-#: ../IkiWiki/CGI.pm:721
-msgid "You are banned."
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1269
+msgid "Error"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:53
+#: ../IkiWiki/Plugin/aggregate.pm:84
msgid "Aggregation triggered via web."
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:62
+#: ../IkiWiki/Plugin/aggregate.pm:93
msgid "Nothing to do right now, all feeds are up-to-date!"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:134
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, perl-format
msgid "missing %s parameter"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:168
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:182
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:184
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:347
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:354
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:381
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
+msgid "last checked %s"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:385
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:390
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:405
+#: ../IkiWiki/Plugin/aggregate.pm:503
msgid "feed not found"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:416
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:422
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:428
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:502
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:30
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
msgid "deleting bucket.."
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:37 ../IkiWiki/Setup/Standard.pm:89
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
msgid "done"
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:46
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
#, perl-format
msgid "Must specify %s"
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:85
-msgid "Failed to create bucket in S3: "
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+msgid "Failed to create S3 bucket: "
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:170
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
msgid "Failed to save file to S3: "
msgstr ""
-#: ../IkiWiki/Plugin/amazon_s3.pm:192
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
msgid "Failed to delete file from S3: "
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:95
-msgid "bad attachment filename"
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:118
-msgid "attachment rejected"
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
msgstr ""
-#: ../IkiWiki/Plugin/attachment.pm:147
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
msgid "attachment upload"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr ""
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, perl-format
+msgid "commenting on %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, perl-format
+msgid "removing old preview %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
msgid "template not specified"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
msgid "match not specified"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
msgid "failed to process"
msgstr ""
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr ""
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
-msgid "failed to find url in html"
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+msgid "missing page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+msgid "not a page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, perl-format
+msgid "%s is an attachment, not a page."
msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
msgid "failed to run graphviz"
msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:56
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+msgid "Image::Magick is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:66 ../IkiWiki/Plugin/img.pm:70
-#: ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, perl-format
msgid "failed to read %s: %s"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:73
+#: ../IkiWiki/Plugin/img.pm:90
#, perl-format
msgid "failed to resize: %s"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:104
+#: ../IkiWiki/Plugin/img.pm:119
#, perl-format
msgid "failed to determine size of image %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:47
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:106
+#: ../IkiWiki/Plugin/inline.pm:138
+msgid "page editing not allowed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:155
msgid "missing pages parameter"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:154
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:225
+#: ../IkiWiki/Plugin/inline.pm:329
msgid "Add a new post titled:"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:241
+#: ../IkiWiki/Plugin/inline.pm:349
#, perl-format
msgid "nonexistant template %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:274 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr ""
-
-#: ../IkiWiki/Plugin/inline.pm:504
+#: ../IkiWiki/Plugin/inline.pm:614
msgid "RPC::XML::Client not found, not pinging"
msgstr ""
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
msgid "failed to run dot"
msgstr ""
-#: ../IkiWiki/Plugin/lockedit.pm:29
+#: ../IkiWiki/Plugin/lockedit.pm:47
#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+msgid "%s is locked and cannot be edited"
msgstr ""
-#: ../IkiWiki/Plugin/mdwn.pm:28
+#: ../IkiWiki/Plugin/mdwn.pm:44
msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
msgstr ""
-#: ../IkiWiki/Plugin/mdwn.pm:51
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
-#: ../IkiWiki/Plugin/meta.pm:137
+#: ../IkiWiki/Plugin/meta.pm:158
msgid "stylesheet not found"
msgstr ""
-#: ../IkiWiki/Plugin/meta.pm:171
+#: ../IkiWiki/Plugin/meta.pm:196
msgid "redir page not found"
msgstr ""
-#: ../IkiWiki/Plugin/meta.pm:184
+#: ../IkiWiki/Plugin/meta.pm:210
msgid "redir cycle is not allowed"
msgstr ""
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr ""
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr ""
msgid "more"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr ""
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr ""
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+msgid "All pages have other pages linking to them."
msgstr ""
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:223
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:226
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:233
+#: ../IkiWiki/Plugin/passwordauth.pm:258
msgid "No email address, so cannot email password reset instructions."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:265
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:267
+#: ../IkiWiki/Plugin/passwordauth.pm:294
msgid "You have been mailed password reset instructions."
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:302
+#: ../IkiWiki/Plugin/passwordauth.pm:329
msgid "incorrect password reset url"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:305
+#: ../IkiWiki/Plugin/passwordauth.pm:332
msgid "password reset denied"
msgstr ""
-#: ../IkiWiki/Plugin/pingee.pm:21
+#: ../IkiWiki/Plugin/pingee.pm:30
msgid "Ping received."
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:37
+#: ../IkiWiki/Plugin/pinger.pm:53
msgid "requires 'from' and 'to' parameters"
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:42
+#: ../IkiWiki/Plugin/pinger.pm:58
#, perl-format
msgid "Will ping %s"
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:45
+#: ../IkiWiki/Plugin/pinger.pm:61
#, perl-format
msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
msgstr ""
-#: ../IkiWiki/Plugin/pinger.pm:61
+#: ../IkiWiki/Plugin/pinger.pm:77
msgid "LWP not found, not pinging"
msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:65
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, perl-format
+msgid "building %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, perl-format
+msgid "failed to update %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, perl-format
+msgid "failed to translate %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, perl-format
+msgid "failed to write %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1058
+msgid "failed to translate"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, perl-format
+msgid "failed to read %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:73
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr ""
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr ""
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
+#: ../IkiWiki/Plugin/polygen.pm:60
+msgid "command failed"
msgstr ""
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr ""
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr ""
msgid "%A night"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:76
-msgid "missing page"
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:78
-#, perl-format
-msgid "The page %s does not exist."
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
msgstr ""
-#: ../IkiWiki/Plugin/recentchangesdiff.pm:26
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
msgid "(Diff truncated)"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:20
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
#, perl-format
-msgid "Must specify %s when using the search plugin"
+msgid "%s does not exist"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:170
+#: ../IkiWiki/Plugin/remove.pm:38
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
+msgid "no change to the file name was specified"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:68
+#, perl-format
+msgid "illegal name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:73
+#, perl-format
+msgid "%s already exists"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, perl-format
+msgid "rename %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, perl-format
+msgid "update for rename of %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/search.pm:182
#, perl-format
msgid "need Digest::SHA1 to index %s"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:203
+#: ../IkiWiki/Plugin/search.pm:217
msgid "search"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/shortcut.pm:44
msgid "missing name or url parameter"
msgstr ""
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr ""
-#: ../IkiWiki/Plugin/smiley.pm:32
+#: ../IkiWiki/Plugin/smiley.pm:43
msgid "failed to parse any smileys"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
msgid "parse error"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:95
-msgid "bad height value"
+#: ../IkiWiki/Plugin/sparkline.pm:104
+msgid "invalid height value"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
msgid "missing width parameter"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:106
-msgid "bad width value"
+#: ../IkiWiki/Plugin/sparkline.pm:115
+msgid "invalid width value"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
msgid "failed to run php"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, perl-format
msgid "parse fail at line %d: %s"
msgstr ""
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
msgid "missing id parameter"
msgstr ""
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr ""
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
msgid "failed to process:"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:88
+#: ../IkiWiki/Plugin/teximg.pm:128
msgid "failed to generate image from code"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:69
-msgid "getctime not implemented"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
msgstr ""
-#: ../IkiWiki/Render.pm:286 ../IkiWiki/Render.pm:307
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:85
+#, perl-format
+msgid "bad file name %s"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr ""
-#: ../IkiWiki/Render.pm:361
+#: ../IkiWiki/Render.pm:294
#, perl-format
-msgid "removing old page %s"
+msgid "%s has multiple possible source pages"
msgstr ""
-#: ../IkiWiki/Render.pm:401
+#: ../IkiWiki/Render.pm:380
#, perl-format
-msgid "scanning %s"
+msgid "removing old page %s"
msgstr ""
-#: ../IkiWiki/Render.pm:406
+#: ../IkiWiki/Render.pm:421
#, perl-format
-msgid "rendering %s"
+msgid "scanning %s"
msgstr ""
-#: ../IkiWiki/Render.pm:427
+#: ../IkiWiki/Render.pm:447
#, perl-format
-msgid "rendering %s, which links to %s"
+msgid "building %s, which links to %s"
msgstr ""
-#: ../IkiWiki/Render.pm:448
+#: ../IkiWiki/Render.pm:473
#, perl-format
-msgid "rendering %s, which depends on %s"
+msgid "building %s, which depends on %s"
msgstr ""
-#: ../IkiWiki/Render.pm:487
+#: ../IkiWiki/Render.pm:513
#, perl-format
-msgid "rendering %s, to update its backlinks"
+msgid "building %s, to update its backlinks"
msgstr ""
-#: ../IkiWiki/Render.pm:499
+#: ../IkiWiki/Render.pm:525
#, perl-format
-msgid "removing %s, no longer rendered by %s"
+msgid "removing %s, no longer built by %s"
msgstr ""
-#: ../IkiWiki/Render.pm:523
+#: ../IkiWiki/Render.pm:549
#, perl-format
-msgid "ikiwiki: cannot render %s"
+msgid "ikiwiki: cannot build %s"
msgstr ""
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:79
-msgid "rebuilding wiki.."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:82
-msgid "refreshing wiki.."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
+
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
msgstr ""
#: ../IkiWiki/Wrapper.pm:16
msgid "wrapper filename not specified"
msgstr ""
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr ""
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr ""
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr ""
msgid "usage: ikiwiki [options] source dest"
msgstr ""
-#: ../ikiwiki.in:82
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:124
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr ""
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr ""
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr ""
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr ""
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
-#: ../IkiWiki.pm:193 ../IkiWiki.pm:194
-msgid "Error"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
+
+#: ../IkiWiki.pm:569
+#, perl-format
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1251
+#, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:764
+#: ../IkiWiki.pm:1791
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "cannot match pages: %s"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
msgstr ""
--- /dev/null
+# Italian translation of ikiwiki.
+# This file is distributed under the same license as the ikiwiki package.
+# Luca Bruno <lucab@debian.org>, 2009.
+msgid ""
+msgstr ""
+"Project-Id-Version: Ikiwiki\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-25 18:43-0400\n"
+"PO-Revision-Date: 2009-08-16 11:01+0100\n"
+"Last-Translator: Luca Bruno <lucab@debian.org>\n"
+"Language-Team: Italian TP <tp@lists.linux.it>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../IkiWiki/CGI.pm:113
+msgid "You need to log in first."
+msgstr "Occorre prima effettuare l'accesso."
+
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+"possibile errore di configurazione: sslcookie è impostato, ma si sta "
+"tentando un accesso via http, non https"
+
+#: ../IkiWiki/CGI.pm:149
+msgid "login failed, perhaps you need to turn on cookies?"
+msgstr "errore nell'accesso, probabilmente i cookie sono disabilitati?"
+
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr "La sessione è scaduta."
+
+#: ../IkiWiki/CGI.pm:189
+msgid "Login"
+msgstr "Entra"
+
+#: ../IkiWiki/CGI.pm:190
+msgid "Preferences"
+msgstr "Preferenze"
+
+#: ../IkiWiki/CGI.pm:191
+msgid "Admin"
+msgstr "Amministrazione"
+
+#: ../IkiWiki/CGI.pm:231
+msgid "Preferences saved."
+msgstr "Preferenze salvate."
+
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Avete ricevuto un ban."
+
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1269
+msgid "Error"
+msgstr "Errore"
+
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr "Aggregazione attivata dal web."
+
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
+"Nessuna azione da intraprendere, tutti i notiziari sono già aggiornati."
+
+#: ../IkiWiki/Plugin/aggregate.pm:220
+#, perl-format
+msgid "missing %s parameter"
+msgstr "parametro %s mancante"
+
+#: ../IkiWiki/Plugin/aggregate.pm:255
+msgid "new feed"
+msgstr "nuovo notiziario"
+
+#: ../IkiWiki/Plugin/aggregate.pm:269
+msgid "posts"
+msgstr "articoli"
+
+#: ../IkiWiki/Plugin/aggregate.pm:271
+msgid "new"
+msgstr "nuovo"
+
+#: ../IkiWiki/Plugin/aggregate.pm:441
+#, perl-format
+msgid "expiring %s (%s days old)"
+msgstr "in scadenza %s (vecchio di %s giorni)"
+
+#: ../IkiWiki/Plugin/aggregate.pm:448
+#, perl-format
+msgid "expiring %s"
+msgstr "in scadenza %s"
+
+#: ../IkiWiki/Plugin/aggregate.pm:475
+#, perl-format
+msgid "last checked %s"
+msgstr "ultimo controllo %s"
+
+#: ../IkiWiki/Plugin/aggregate.pm:479
+#, perl-format
+msgid "checking feed %s ..."
+msgstr "controllo notiziario %s..."
+
+#: ../IkiWiki/Plugin/aggregate.pm:484
+#, perl-format
+msgid "could not find feed at %s"
+msgstr "impossibile trovare il notiziario %s"
+
+#: ../IkiWiki/Plugin/aggregate.pm:503
+msgid "feed not found"
+msgstr "notiziario non trovato"
+
+#: ../IkiWiki/Plugin/aggregate.pm:514
+#, perl-format
+msgid "(invalid UTF-8 stripped from feed)"
+msgstr "(codifica UTF-8 non valida eliminata dal notiziario)"
+
+#: ../IkiWiki/Plugin/aggregate.pm:522
+#, perl-format
+msgid "(feed entities escaped)"
+msgstr "(entità del notiziario espanse con escape)"
+
+#: ../IkiWiki/Plugin/aggregate.pm:530
+msgid "feed crashed XML::Feed!"
+msgstr "il notiziario ha fatto andare in crash XML::Feed."
+
+#: ../IkiWiki/Plugin/aggregate.pm:616
+#, perl-format
+msgid "creating new page %s"
+msgstr "creazione nuova pagina %s"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr "eliminazione contenitore..."
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "fatto"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr "Occorre specificare %s"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+msgid "Failed to create S3 bucket: "
+msgstr "Impossibile creare il contenitore S3: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+msgid "Failed to save file to S3: "
+msgstr "Impossibile salvare il file sul S3: "
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+msgid "Failed to delete file from S3: "
+msgstr "Impossibile eliminare il file dal S3: "
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr "esiste già una pagina chiamata %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr "non permesso da allowed_attachments"
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr "nome file dell'allegato non valido"
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr "carica allegato"
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr "generazione automatica dell'indice"
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+"È stato riconosciuto come spam da <a href=\"http://blogspam.net/\">blogspam</"
+"a>: "
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
+#, perl-format
+msgid "%s from %s"
+msgstr "%s da %s"
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
+msgid "There are no broken links!"
+msgstr "Non ci sono collegamenti rotti."
+
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr "formato pagina %s non supportato"
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr "i commenti devono avere un contenuto"
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr "Anonimo"
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr "nome pagina non valido"
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, perl-format
+msgid "commenting on %s"
+msgstr "commento su %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr "la pagina «%s» non esiste, impossibile commentarla"
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr "i commenti per la pagina «%s» sono chiusi"
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr "commento trattenuto per moderazione"
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr "Il commento sarà pubblicato dopo la verifica del moderatore"
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr "Aggiunto commento"
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr "Aggiunto commento: %s"
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr "non siete autenticati come amministratore"
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr "Moderazione commenti"
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr "moderazione commento"
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr "Commenti"
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
+#, perl-format
+msgid "%s parameter is required"
+msgstr "parametro %s necessario"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr "nessun testo è stato copiato in questa pagina"
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr "nessun testo è stato copiato in questa pagina con l'id %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, perl-format
+msgid "removing old preview %s"
+msgstr "rimozione vecchia anteprima %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "%s non è una pagina modificabile"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "creazione %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "modifica %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
+msgid "template not specified"
+msgstr "modello non specificato"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:54
+msgid "match not specified"
+msgstr "corrispondenza non specificata"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:62
+#, perl-format
+msgid "edittemplate %s registered for %s"
+msgstr "edittemplate %s registrato per %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:133
+msgid "failed to process"
+msgstr "errore nell'elaborazione"
+
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr "occorre specificare formato e testo"
+
+#: ../IkiWiki/Plugin/fortune.pm:27
+msgid "fortune failed"
+msgstr "errore nel fortune"
+
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+msgid "missing page"
+msgstr "pagina mancante"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr "La pagina %s non esiste."
+
+#: ../IkiWiki/Plugin/getsource.pm:73
+msgid "not a page"
+msgstr "non è una pagina"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "%s è un allegato, non una pagina."
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr "non è permesso modificare %s"
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr "non è permesso lavorare su un file in modalità %s"
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr "non è permesso cambiare la modalità del file"
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Occorre specificare %s quando si usa il plugin %s"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+"Errore nell'interpretazione dell'URL, impossibile determinare il nome del "
+"dominio"
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
+msgid "failed to run graphviz"
+msgstr "errore nell'eseguire graphviz"
+
+#: ../IkiWiki/Plugin/graphviz.pm:94
+msgid "prog not a valid graphviz program"
+msgstr "prog non è un programma graphviz valido"
+
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr "tohighlight contiene il tipo di file sconosciuto «%s»"
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr "Sorgente: %s"
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+"attenzione: modulo perl highlight non trovato, verrà passato inalterato"
+
+#: ../IkiWiki/Plugin/img.pm:63
+msgid "Image::Magick is not installed"
+msgstr "Image::Magick non è installato"
+
+#: ../IkiWiki/Plugin/img.pm:72
+#, perl-format
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr "Formato dimensione «%s» non valido (dovrebbe essere LxA)"
+
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
+#, perl-format
+msgid "failed to read %s: %s"
+msgstr "impossibile leggere %s: %s"
+
+#: ../IkiWiki/Plugin/img.pm:90
+#, perl-format
+msgid "failed to resize: %s"
+msgstr "impossibile ridimensionare: %s"
+
+#: ../IkiWiki/Plugin/img.pm:119
+#, perl-format
+msgid "failed to determine size of image %s"
+msgstr "impossibile determinare la dimensione dell'immagine %s"
+
+#: ../IkiWiki/Plugin/inline.pm:92
+msgid "Must specify url to wiki with --url when using --rss or --atom"
+msgstr ""
+"Occorre specificare l'url del wiki tramite --url quando si usa --rss o --atom"
+
+#: ../IkiWiki/Plugin/inline.pm:138
+msgid "page editing not allowed"
+msgstr "modifica della pagina non ammessa"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+msgid "missing pages parameter"
+msgstr "parametro pagine mancante"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr "i parametri %s e %s non possono essere usati insieme"
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr "Sort::Naturally è richiesto per l'ordinamento title_natural"
+
+#: ../IkiWiki/Plugin/inline.pm:223
+#, perl-format
+msgid "unknown sort type %s"
+msgstr "ordinamento %s sconosciuto"
+
+#: ../IkiWiki/Plugin/inline.pm:329
+msgid "Add a new post titled:"
+msgstr "Aggiungere un nuovo articolo dal titolo:"
+
+#: ../IkiWiki/Plugin/inline.pm:349
+#, perl-format
+msgid "nonexistant template %s"
+msgstr "modello %s non esistente"
+
+#: ../IkiWiki/Plugin/inline.pm:614
+msgid "RPC::XML::Client not found, not pinging"
+msgstr "RPC::XML::Client non trovato, impossibile inviare ping"
+
+#: ../IkiWiki/Plugin/linkmap.pm:106
+msgid "failed to run dot"
+msgstr "impossibile eseguire dot"
+
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, perl-format
+msgid "%s is locked and cannot be edited"
+msgstr "%s è bloccata e non può essere modificata"
+
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+"multimarkdown è stato abilitato, ma Text::MultiMarkdown non è aggiornato"
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
+#, perl-format
+msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
+msgstr ""
+"impossibile caricare il modulo perl Markdown.pm (%s) o /usr/bin/markdown (%s)"
+
+#: ../IkiWiki/Plugin/meta.pm:158
+msgid "stylesheet not found"
+msgstr "foglio di stile non trovato"
+
+#: ../IkiWiki/Plugin/meta.pm:196
+msgid "redir page not found"
+msgstr "pagina di reindirizzamento non trovata"
+
+#: ../IkiWiki/Plugin/meta.pm:210
+msgid "redir cycle is not allowed"
+msgstr "ciclo di reindirizzamento non ammesso"
+
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
+msgid "Mirrors"
+msgstr "Mirror"
+
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
+msgid "Mirror"
+msgstr "Mirror"
+
+#: ../IkiWiki/Plugin/more.pm:8
+msgid "more"
+msgstr "altro"
+
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime non implementata"
+
+#: ../IkiWiki/Plugin/openid.pm:61
+msgid "Log in with"
+msgstr "Accedi tramite"
+
+#: ../IkiWiki/Plugin/openid.pm:64
+msgid "Get an OpenID"
+msgstr "Ottieni un OpenID"
+
+#: ../IkiWiki/Plugin/orphans.pm:45
+msgid "All pages have other pages linking to them."
+msgstr "Tutte le pagine hanno collegamenti in entrata da altre pagine."
+
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
+msgid "bad or missing template"
+msgstr "modello errato o mancante"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:248
+msgid "Account creation successful. Now you can Login."
+msgstr "Account creato con successo. È ora possibile effettuare l'accesso."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:251
+msgid "Error creating account."
+msgstr "Errore nella creazione dell'account."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+"Nessun indirizzo email, impossibile inviare per email le istruzioni per "
+"reimpostare la password."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
+msgid "Failed to send mail"
+msgstr "Impossibile spedire il messaggio"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+"Il messaggio con le istruzioni per reimpostare la password è stato inviato."
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr "url per il reset della password non corretto"
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr "reset della password non permesso"
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr "Ping ricevuto."
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr "sono richiesti i parametri \"to\" e \"from\""
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, perl-format
+msgid "Will ping %s"
+msgstr "Verrà inviato un ping a %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr "Ignorata la richiesta di ping per il wiki %s (questo wiki è %s)"
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+msgid "LWP not found, not pinging"
+msgstr "LWP non trovato, ping non inviato"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+"attenzione: è presente un vecchio po4a. Si raccomanda di aggiornare almeno "
+"alla versione 0.35."
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr "%s non è una codifica di lingua valida"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+"%s non è un valore per po_link_to valido, verrà utilizzato po_link_to=default"
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+"po_link_to=negotiated richiede che venga abilitato usedirs, verrà utilizzato "
+"po_link_to=default"
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr "rigenerazione di tutte le pagine per sistemare i meta-titoli"
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, perl-format
+msgid "building %s"
+msgstr "compilazione di %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr "file PO aggiornati"
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+"Impossibile eliminare una traduzione. Tuttavia, se la pagina principale è "
+"stata eliminata anche le traduzioni lo saranno."
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+"Impossibile rinominare una traduzione. Tuttavia, se la pagina principale è "
+"stata rinominata anche le traduzioni lo saranno."
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr "Il file POT (%s) non esiste"
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "impossibile copiare il file PO di underlay in %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, perl-format
+msgid "failed to update %s"
+msgstr "impossibile aggiornare %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "impossibile copiare il file POT in %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr "N/D"
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, perl-format
+msgid "failed to translate %s"
+msgstr "impossibile tradurre %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr "file PO obsoleti rimossi"
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, perl-format
+msgid "failed to write %s"
+msgstr "impossibile scrivere %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+msgid "failed to translate"
+msgstr "impossibile tradurre"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, perl-format
+msgid "failed to read %s"
+msgstr "impossibile leggere %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+"dati gettext non validi, tornare alle pagina precedente per continuare le "
+"modifiche"
+
+#: ../IkiWiki/Plugin/poll.pm:69
+msgid "vote"
+msgstr "voto"
+
+#: ../IkiWiki/Plugin/poll.pm:77
+msgid "Total votes:"
+msgstr "Voti totali:"
+
+#: ../IkiWiki/Plugin/polygen.pm:41
+msgid "polygen not installed"
+msgstr "polygen non è installato"
+
+#: ../IkiWiki/Plugin/polygen.pm:60
+msgid "command failed"
+msgstr "errore nel comando"
+
+#: ../IkiWiki/Plugin/postsparkline.pm:41
+msgid "missing formula"
+msgstr "formula mancante"
+
+#: ../IkiWiki/Plugin/postsparkline.pm:48
+msgid "unknown formula"
+msgstr "formula sconosciuta"
+
+#. translators: These descriptions of times of day are used
+#. translators: in messages like "last edited <description>".
+#. translators: %A is the name of the day of the week, while
+#. translators: %A- is the name of the previous day.
+#: ../IkiWiki/Plugin/prettydate.pm:15
+msgid "late %A- night"
+msgstr "%A- a tarda notte"
+
+#: ../IkiWiki/Plugin/prettydate.pm:17
+msgid "in the wee hours of %A- night"
+msgstr "%A prima dell'alba"
+
+#: ../IkiWiki/Plugin/prettydate.pm:20
+msgid "terribly early %A morning"
+msgstr "%A mattina molto presto"
+
+#: ../IkiWiki/Plugin/prettydate.pm:22
+msgid "early %A morning"
+msgstr "%A mattina presto"
+
+#: ../IkiWiki/Plugin/prettydate.pm:25
+msgid "mid-morning %A"
+msgstr "%A metà mattina"
+
+#: ../IkiWiki/Plugin/prettydate.pm:26
+msgid "late %A morning"
+msgstr "%A mattina tardi"
+
+#: ../IkiWiki/Plugin/prettydate.pm:27
+msgid "at lunch time on %A"
+msgstr "%A all'ora di pranzo"
+
+#: ../IkiWiki/Plugin/prettydate.pm:29
+msgid "%A afternoon"
+msgstr "%A pomeriggio"
+
+#: ../IkiWiki/Plugin/prettydate.pm:32
+msgid "late %A afternoon"
+msgstr "%A pomeriggio tardo"
+
+#: ../IkiWiki/Plugin/prettydate.pm:33
+msgid "%A evening"
+msgstr "%A sera"
+
+#: ../IkiWiki/Plugin/prettydate.pm:35
+msgid "late %A evening"
+msgstr "%A sera tardi"
+
+#: ../IkiWiki/Plugin/prettydate.pm:37
+msgid "%A night"
+msgstr "%A notte"
+
+#: ../IkiWiki/Plugin/prettydate.pm:101
+msgid "at teatime on %A"
+msgstr "%A all'ora di merenda"
+
+#: ../IkiWiki/Plugin/prettydate.pm:105
+msgid "at midnight"
+msgstr "a mezzanotte"
+
+#: ../IkiWiki/Plugin/prettydate.pm:108
+msgid "at noon on %A"
+msgstr "%A a mezzogiorno"
+
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr "valore percentuale %s non ammesso"
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+"occorrono alternativamente i parametri \"percent\" o \"totalpages\" e "
+"\"donepages\""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr "(Diff troncato)"
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr "%s non esiste"
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s non è in src, quindi non può essere eliminato"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr "%s non è un file"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr "conferma rimozione di %s"
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr "Selezionare l'allegato da rimuovere."
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr "rimosso"
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr "%s non è in src, quindi non può essere rinominato"
+
+#: ../IkiWiki/Plugin/rename.pm:62
+msgid "no change to the file name was specified"
+msgstr "non è stata specificata nessuna modifica al nome del file"
+
+#: ../IkiWiki/Plugin/rename.pm:68
+#, perl-format
+msgid "illegal name"
+msgstr "nome non valido"
+
+#: ../IkiWiki/Plugin/rename.pm:73
+#, perl-format
+msgid "%s already exists"
+msgstr "%s esiste già"
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr "%s già presente su disco"
+
+#: ../IkiWiki/Plugin/rename.pm:122
+#, perl-format
+msgid "rename %s"
+msgstr "rinomina di %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr "Rinomina anche SottoPagine e allegati"
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr "Si può rinominare un solo allegato alla volta."
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr "Selezionare l'allegato da rinominare."
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr "rinomina %s in %s"
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, perl-format
+msgid "update for rename of %s to %s"
+msgstr "aggiornamento per rinomina di %s in %s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr "è necessario Digest::SHA1 per l'indice di %s"
+
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr "cerca"
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr "il plugin scorciatoia non può funzionare senza %s"
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
+msgid "missing name or url parameter"
+msgstr "parametro nome o url mancante"
+
+#. translators: This is used to display what shortcuts are defined.
+#. translators: First parameter is the name of the shortcut, the second
+#. translators: is an URL.
+#: ../IkiWiki/Plugin/shortcut.pm:54
+#, perl-format
+msgid "shortcut %s points to <i>%s</i>"
+msgstr "la scorciatoia %s punta a <i>%s</i>"
+
+#: ../IkiWiki/Plugin/smiley.pm:43
+msgid "failed to parse any smileys"
+msgstr "impossibile interpretare gli smile"
+
+#: ../IkiWiki/Plugin/sparkline.pm:72
+msgid "parse error"
+msgstr "errore nell'interpretazione"
+
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
+msgstr "Diametro featurepoint non valido"
+
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
+msgstr "Posizione featurepoint non valida"
+
+#: ../IkiWiki/Plugin/sparkline.pm:99
+msgid "missing values"
+msgstr "valori mancanti"
+
+#: ../IkiWiki/Plugin/sparkline.pm:104
+msgid "invalid height value"
+msgstr "valore altezza non valido"
+
+#: ../IkiWiki/Plugin/sparkline.pm:111
+msgid "missing width parameter"
+msgstr "parametro larghezza mancante"
+
+#: ../IkiWiki/Plugin/sparkline.pm:115
+msgid "invalid width value"
+msgstr "valore larghezza non valido"
+
+#: ../IkiWiki/Plugin/sparkline.pm:153
+msgid "failed to run php"
+msgstr "impossibile eseguire php"
+
+#: ../IkiWiki/Plugin/table.pm:31
+msgid "cannot find file"
+msgstr "impossibile trovare il file"
+
+#: ../IkiWiki/Plugin/table.pm:87
+msgid "unknown data format"
+msgstr "formato dati sconosiuto"
+
+#: ../IkiWiki/Plugin/table.pm:95
+msgid "empty data"
+msgstr "nessun dato"
+
+#: ../IkiWiki/Plugin/table.pm:114
+msgid "Direct data download"
+msgstr "Scaricamento diretto dei dati"
+
+#: ../IkiWiki/Plugin/table.pm:148
+#, perl-format
+msgid "parse fail at line %d: %s"
+msgstr "errore di interpretazione alla riga %d: %s"
+
+#: ../IkiWiki/Plugin/template.pm:29
+msgid "missing id parameter"
+msgstr "parametro id mancante"
+
+#: ../IkiWiki/Plugin/template.pm:36
+#, perl-format
+msgid "template %s not found"
+msgstr "modello %s non trovato"
+
+#: ../IkiWiki/Plugin/template.pm:55
+msgid "failed to process:"
+msgstr "errore nell'elaborazione:"
+
+#: ../IkiWiki/Plugin/teximg.pm:70
+msgid "missing tex code"
+msgstr "codice tex mancante"
+
+#: ../IkiWiki/Plugin/teximg.pm:77
+msgid "code includes disallowed latex commands"
+msgstr "nel codice sono presenti comandi latex non permessi"
+
+#: ../IkiWiki/Plugin/teximg.pm:128
+msgid "failed to generate image from code"
+msgstr "impossibile generare l'immagine dal codice"
+
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
+msgstr "plugin"
+
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr "abilitare %s?"
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr "il file di setup di questo wiki non è noto"
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr "principale"
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr "plugin"
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+"Le sottostanti modifiche alla configurazione richiedono la ricompilazione "
+"del wiki."
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+"Affinché le sottostanti modifiche alla configurazione abbiano effetto, "
+"occorre ricostruire il wiki."
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr "Errore: %s è terminato con errore (%s). Modifiche al setup scartate."
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr "impossibile determinare l'id del committer non fidato %s"
+
+#: ../IkiWiki/Receive.pm:85
+#, perl-format
+msgid "bad file name %s"
+msgstr "nome file %s scorretto"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+"collegamento simbolico trovato nel percorso srcdir (%s) -- impostare "
+"allow_symlinks_before_srcdir per abilitare questa configurazione"
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
+#, perl-format
+msgid "skipping bad filename %s"
+msgstr "ignorato il file dal nome scorretto %s"
+
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr "%s ha diverse pagine sorgenti possibili"
+
+#: ../IkiWiki/Render.pm:380
+#, perl-format
+msgid "removing old page %s"
+msgstr "rimozione della vecchia pagina %s"
+
+#: ../IkiWiki/Render.pm:421
+#, perl-format
+msgid "scanning %s"
+msgstr "scansione %s"
+
+#: ../IkiWiki/Render.pm:447
+#, perl-format
+msgid "building %s, which links to %s"
+msgstr "compilazione di %s, che è collegato a %s"
+
+#: ../IkiWiki/Render.pm:473
+#, perl-format
+msgid "building %s, which depends on %s"
+msgstr "compilazione di %s, che dipende da %s"
+
+#: ../IkiWiki/Render.pm:513
+#, perl-format
+msgid "building %s, to update its backlinks"
+msgstr "compilazione di %s, per aggiornare i collegamenti ai precedenti"
+
+#: ../IkiWiki/Render.pm:525
+#, perl-format
+msgid "removing %s, no longer built by %s"
+msgstr "rimozione di %s, non più richiesto da %s"
+
+#: ../IkiWiki/Render.pm:549
+#, perl-format
+msgid "ikiwiki: cannot build %s"
+msgstr "ikiwiki: impossibile compilare %s"
+
+#. translators: The first parameter is a filename, and the second
+#. translators: is a (probably not translated) error message.
+#: ../IkiWiki/Setup.pm:19
+#, perl-format
+msgid "cannot read %s: %s"
+msgstr "impossibile leggere %s: %s"
+
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr "occorre inserire un wikiname (contente caratteri alfanumerici)"
+
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr "sistema di controllo di revisione %s non supportato"
+
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr "impossibile creare un repository tramite ikiwiki-makerepo"
+
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
+"** Plugin %s disabilitato, a causa della seguente segnalazione di errore:"
+
+#: ../IkiWiki/Wrapper.pm:16
+#, perl-format
+msgid "%s doesn't seem to be executable"
+msgstr "%s non sembra essere eseguibile"
+
+#: ../IkiWiki/Wrapper.pm:20
+msgid "cannot create a wrapper that uses a setup file"
+msgstr "impossibile creare un contenitore che utilizzi un file di setup"
+
+#: ../IkiWiki/Wrapper.pm:24
+msgid "wrapper filename not specified"
+msgstr "nome del file del contenitore non specificato"
+
+#. translators: The parameter is a C filename.
+#: ../IkiWiki/Wrapper.pm:152
+#, perl-format
+msgid "failed to compile %s"
+msgstr "errore nel compilare %s"
+
+#. translators: The parameter is a filename.
+#: ../IkiWiki/Wrapper.pm:172
+#, perl-format
+msgid "successfully generated %s"
+msgstr "%s generato con successo"
+
+#: ../ikiwiki.in:13
+msgid "usage: ikiwiki [options] source dest"
+msgstr "utilizzo: ikiwiki [opzioni] sorgente destinazione"
+
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr " ikiwiki --setup configfile"
+
+#: ../ikiwiki.in:91
+msgid "usage: --set var=value"
+msgstr "utilizzo: --set var=valore"
+
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "generazione contenitori..."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "ricostruzione wiki..."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "aggiornamento wiki..."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Discussione"
+
+#: ../IkiWiki.pm:494
+msgid "Must specify url to wiki with --url when using --cgi"
+msgstr "Occorre specificare l'url del wiki tramite --url quando si usa --cgi"
+
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr "impossibile usare più plugin rcs"
+
+#: ../IkiWiki.pm:569
+#, perl-format
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr "impossibile caricare il plugin esterno per il plugin %s: %s"
+
+#: ../IkiWiki.pm:1251
+#, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
+msgstr "ciclo del preprocessore individuato su %s alla profondità %i"
+
+#: ../IkiWiki.pm:1791
+msgid "yes"
+msgstr "sì"
+
+#: ../IkiWiki.pm:1915
+#, perl-format
+msgid "cannot match pages: %s"
+msgstr "impossibile trovare pagine corrispondenti: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr "Quale sarà il nome del wiki?"
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr "wiki"
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr "Che sistema di controllo di revisione usare?"
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr "Quale utente (openid o del wiki) sarà l'amministratore?"
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr "Qual è il nome del dominio del server web?"
msgstr ""
"Project-Id-Version: ikiwiki 1.51\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
"PO-Revision-Date: 2007-04-27 22:05+0200\n"
"Last-Translator: Pawel Tecza <ptecza@net.icm.edu.pl>\n"
"Language-Team: Debian L10n Polish <debian-l10n-polish@lists.debian.org>\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Proszę najpierw zalogować się."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
"Nieudane logowanie. Proszę sprawdzić czy w przeglądarce włączone są "
"ciasteczka (ang. cookies)"
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr ""
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
#, fuzzy
msgid "Preferences"
msgstr "Preferencje zapisane."
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr ""
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Preferencje zapisane."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr "Strona %s nie może być edytowana"
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "dyskusja"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Twój dostęp został zabroniony przez administratora."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "tworzenie %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Błąd"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "edycja %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr ""
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "Twój dostęp został zabroniony przez administratora."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, fuzzy, perl-format
msgid "missing %s parameter"
msgstr "brakujący parametr %s"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "nowy kanał RSS"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "wpisy"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "nowy wpis"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "wygasający wpis %s (ma już %s dni)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "wygasający wpis %s"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "kanał RSS przetworzony w dniu %s"
+msgid "last checked %s"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "sprawdzanie kanału RSS %s..."
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "nie znaleziono kanału RSS pod adresem %s"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
#, fuzzy
msgid "feed not found"
msgstr "nieznaleziony kanał RSS"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, fuzzy, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr "Nieprawidłowe kodowanie UTF-8 usunięte z kanału RSS"
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "awaria kanału RSS w module XML::Feed!"
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "tworzenie nowej strony %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "gotowe"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Awaria w trakcie wysyłania wiadomości"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Awaria w trakcie wysyłania wiadomości"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "awaria w trakcie zmiany rozmiaru: %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr ""
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "Wszystkie odnośniki są aktualne!"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, fuzzy, perl-format
+msgid "commenting on %s"
+msgstr "tworzenie %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, fuzzy, perl-format
msgid "%s parameter is required"
msgstr "Parametry \"test\" i \"then\" są wymagane"
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, fuzzy, perl-format
+msgid "removing old preview %s"
+msgstr "usuwanie starej strony %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr "Strona %s nie może być edytowana"
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "tworzenie %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "edycja %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
#, fuzzy
msgid "template not specified"
msgstr "nieznaleziony szablon %s"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
#, fuzzy
msgid "match not specified"
msgstr "nieokreślona nazwa pliku osłony"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
#, fuzzy
msgid "failed to process"
msgstr "awaria w trakcie przetwarzania:"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "awaria fortunki"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+#, fuzzy
+msgid "missing page"
+msgstr "brakujące wartości"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
#, fuzzy
-msgid "failed to find url in html"
-msgstr "awaria w trakcie wyszukiwania adresu URL na stronie HTML"
+msgid "not a page"
+msgstr "awaria w trakcie odczytu %s: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, fuzzy, perl-format
+msgid "%s is an attachment, not a page."
+msgstr "Strona %s nie może być edytowana"
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
+
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Wtyczka do wyszukiwarka wymaga podania %s"
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
#, fuzzy
msgid "failed to run graphviz"
msgstr "awaria w trakcie uruchamiania wtyczki graphviz"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr "prog nie jest poprawnym programem graphviz"
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+#, fuzzy
+msgid "Image::Magick is not installed"
+msgstr "wtyczka polygen nie jest zainstalowana"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
-msgstr "nieprawidłowy rozmiar \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
+msgstr ""
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, fuzzy, perl-format
msgid "failed to read %s: %s"
msgstr "awaria w trakcie odczytu %s: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, fuzzy, perl-format
msgid "failed to resize: %s"
msgstr "awaria w trakcie zmiany rozmiaru: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, fuzzy, perl-format
msgid "failed to determine size of image %s"
msgstr "awaria w trakcie zmiany rozmiaru: %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
"Użycie parametru --rss lub --atom wymaga podania adresu URL do wiki za "
"pomocą parametru --url"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+#, fuzzy
+msgid "page editing not allowed"
+msgstr "nieznaleziony kanał RSS"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+#, fuzzy
+msgid "missing pages parameter"
+msgstr "brakujący parametr %s"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "nieznany sposób sortowania %s"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr "Tytuł nowego wpisu"
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr "brakujący szablon %s"
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Dyskusja"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "Nieznaleziony moduł RPC::XML::Client, brak możliwości pingowania"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
#, fuzzy
msgid "failed to run dot"
msgstr "awaria w trakcie uruchamiania dot"
-#: ../IkiWiki/Plugin/lockedit.pm:29
-#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, fuzzy, perl-format
+msgid "%s is locked and cannot be edited"
msgstr ""
"strona %s jest tymczasowo zablokowana przez użytkownika %s i nie może być "
"teraz edytowana"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"Awaria w trakcie ładowania perlowego modułu Markdown.pm (%s) lub "
"uruchamiania programu /usr/bin/markdown (%s)"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
#, fuzzy
msgid "stylesheet not found"
msgstr "nieznaleziony szablon ze stylami CSS"
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
#, fuzzy
msgid "redir page not found"
msgstr "nieznaleziony kanał RSS"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
#, fuzzy
msgid "redir cycle is not allowed"
msgstr "nieznaleziony kanał RSS"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Kopie lustrzane"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Kopia lustrzana"
msgid "more"
msgstr "więcej"
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "niedostępna funkcja getctime"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Pobierz OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "Dla każdej strony istnieje odnośnik z innej strony"
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Konto założone pomyślnie. Teraz można zalogować się."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Błąd w trakcie zakładania konta."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Awaria w trakcie wysyłania wiadomości"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Wiadomość z hasłem została wysłana."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, fuzzy, perl-format
+msgid "Will ping %s"
+msgstr "edycja %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+#, fuzzy
+msgid "LWP not found, not pinging"
+msgstr "Nieznaleziony moduł RPC::XML::Client, brak możliwości pingowania"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, fuzzy, perl-format
+msgid "%s is not a valid language code"
+msgstr "Strona %s nie może być edytowana"
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "edycja %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "awaria w trakcie kompilowania %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "awaria w trakcie kompilowania %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "awaria w trakcie kompilowania %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "awaria w trakcie zmiany rozmiaru: %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "awaria w trakcie zapisu %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "awaria w trakcie uruchamiania dot"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "awaria w trakcie odczytu %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "głosuj"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Oddane głosy:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "wtyczka polygen nie jest zainstalowana"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "awaria wtyczki polygen"
+#: ../IkiWiki/Plugin/polygen.pm:60
+#, fuzzy
+msgid "command failed"
+msgstr "awaria fortunki"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr "brakująca reguła"
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr "nieznana reguła"
msgid "%A night"
msgstr "nocą w %A"
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr "w porze śniadaniowej w %A"
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr "o północy"
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr "w południe w %A"
-#: ../IkiWiki/Plugin/recentchanges.pm:74
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, fuzzy, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr ""
+"strona %s jest tymczasowo zablokowana przez użytkownika %s i nie może być "
+"teraz edytowana"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, fuzzy, perl-format
+msgid "%s is not a file"
+msgstr "Strona %s nie może być edytowana"
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
#, fuzzy
-msgid "missing page"
-msgstr "brakujące wartości"
+msgid "no change to the file name was specified"
+msgstr "nieokreślona nazwa pliku osłony"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "The page %s does not exist."
+msgid "illegal name"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:73
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Wtyczka do wyszukiwarka wymaga podania %s"
+msgid "%s already exists"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "czyszczanie indeksu z wynikami wtyczki hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:122
+#, fuzzy, perl-format
+msgid "rename %s"
+msgstr "renderowanie %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, fuzzy, perl-format
+msgid "update for rename of %s to %s"
+msgstr "aktualizacja stron wiki %s: %s przez użytkownika %s"
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "aktualizacja indeksu z wynikami wtyczki hyperestraier"
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
+msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
#, fuzzy
msgid "missing name or url parameter"
msgstr "brakujący parametr name lub url"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, fuzzy, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "skrót %s wskazuje na adres <i>%s</i>"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
#, fuzzy
msgid "failed to parse any smileys"
msgstr "awaria w trakcie przetwarzania emitoikonki"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
#, fuzzy
msgid "parse error"
msgstr "błąd w trakcie przetwarzania"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+#, fuzzy
+msgid "invalid featurepoint diameter"
msgstr "nieprawidłowa średnica dla featurepoint"
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+#, fuzzy
+msgid "invalid featurepoint location"
msgstr "nieprawidłowe położenie dla featurepoint"
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr "brakujące wartości"
-#: ../IkiWiki/Plugin/sparkline.pm:95
+#: ../IkiWiki/Plugin/sparkline.pm:104
#, fuzzy
-msgid "bad height value"
+msgid "invalid height value"
msgstr "nieprawidłowa wysokość"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
#, fuzzy
msgid "missing width parameter"
msgstr "brakujący parametr width"
-#: ../IkiWiki/Plugin/sparkline.pm:106
+#: ../IkiWiki/Plugin/sparkline.pm:115
#, fuzzy
-msgid "bad width value"
+msgid "invalid width value"
msgstr "nieprawidłowa szerokość"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
#, fuzzy
msgid "failed to run php"
msgstr "awaria w trakcie uruchamiania php"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr "nie można znaleźć pliku"
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr "nieznany format danych"
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr "brak danych"
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr "Bezpośrednie pobieranie danych"
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, fuzzy, perl-format
msgid "parse fail at line %d: %s"
msgstr "awaria w trakcie przetwarzania linii %d: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
#, fuzzy
msgid "missing id parameter"
msgstr "brakujący parametr id"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "nieznaleziony szablon %s"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
#, fuzzy
msgid "failed to process:"
msgstr "awaria w trakcie przetwarzania:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
#, fuzzy
msgid "missing tex code"
msgstr "brakujące wartości"
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
#, fuzzy
msgid "failed to generate image from code"
msgstr "awaria w trakcie zmiany rozmiaru: %s"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "niedostępna funkcja getctime"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:85
+#, fuzzy, perl-format
+msgid "bad file name %s"
+msgstr "pomijanie nieprawidłowej nazwy pliku %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "pomijanie nieprawidłowej nazwy pliku %s"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "usuwanie starej strony %s"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "skanowanie %s"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "renderowanie %s"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "renderowanie %s z odnośnikiem do %s"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "renderowanie %s zależącego od %s"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr "renderowanie %s w celu aktualizacji powrotnych odnośników"
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "usuwanie %s nie tworzonego już przez %s"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: awaria w trakcie tworzenia %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "awaria w trakcie odczytu %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "tworzenie osłon..."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "przebudowywanie wiki..."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "odświeżanie wiki..."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "gotowe"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "nieokreślona nazwa pliku osłony"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "awaria w trakcie zapisu %s: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "awaria w trakcie kompilowania %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "pomyślnie utworzono %s"
msgid "usage: ikiwiki [options] source dest"
msgstr "użycie: ikiwiki [parametry] źródło cel"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "tworzenie osłon..."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "przebudowywanie wiki..."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "odświeżanie wiki..."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Dyskusja"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr ""
"Użycie parametru --cgi wymaga podania adresu URL do wiki za pomocą parametru "
"--url"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "Błąd"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:569
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1243
+#, fuzzy, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr "polecenie preprocesora %s wykryte w %s na głębokości %i"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
+#, fuzzy, perl-format
+msgid "cannot match pages: %s"
+msgstr "awaria w trakcie odczytu %s: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr ""
+
+#~ msgid "discussion"
+#~ msgstr "dyskusja"
+
+#~ msgid "rendering %s"
+#~ msgstr "renderowanie %s"
+
+#, fuzzy
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr "Wtyczka do wyszukiwarka wymaga podania %s"
+
+#~ msgid "bad size \"%s\""
+#~ msgstr "nieprawidłowy rozmiar \"%s\""
+
+#, fuzzy
+#~ msgid "failed to find url in html"
+#~ msgstr "awaria w trakcie wyszukiwania adresu URL na stronie HTML"
+
+#~ msgid "processed ok at %s"
+#~ msgstr "kanał RSS przetworzony w dniu %s"
+
+#~ msgid "Your password has been emailed to you."
+#~ msgstr "Wiadomość z hasłem została wysłana."
+
+#~ msgid "polygen failed"
+#~ msgstr "awaria wtyczki polygen"
+
+#~ msgid "cleaning hyperestraier search index"
+#~ msgstr "czyszczanie indeksu z wynikami wtyczki hyperestraier"
+
+#~ msgid "updating hyperestraier search index"
+#~ msgstr "aktualizacja indeksu z wynikami wtyczki hyperestraier"
+
#, fuzzy
#~ msgid ""
#~ "REV is not set, not running from mtn post-commit hook, cannot send "
#~ "Brak możliwości wysłania powiadomień od Subversion przez \"haczyk\" post-"
#~ "commit z powodu nieustawionego parametru REV"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "aktualizacja stron wiki %s: %s przez użytkownika %s"
-
#, fuzzy
#~ msgid "%s not found"
#~ msgstr "nie znaleziono %s"
--- /dev/null
+#!/usr/bin/perl
+# This program uses the po plugin's internals to convert the po files that
+# it generates back into translated wiki source files that can be used as a
+# underlay for a non-English wiki.
+use warnings;
+use strict;
+use IkiWiki;
+
+# Load the passed setup file and initialize ikiwiki config.
+%config=IkiWiki::defaultconfig();
+require IkiWiki::Setup;
+IkiWiki::Setup::load(shift);
+IkiWiki::loadplugins();
+IkiWiki::checkconfig();
+
+require IkiWiki::Render;
+IkiWiki::srcdir_check();
+my ($files, $pages)=IkiWiki::find_src_files();
+
+foreach my $file (@$files) {
+ my $page=pagename($file);
+ $pagesources{$page}=$file; # used by po plugin functions
+}
+
+foreach my $ll (keys %{$config{po_slave_languages}}) {
+ $config{destdir}="../underlays/locale/$ll";
+
+ foreach my $file (@$files) {
+ my $page=pagename($file);
+ my ($masterpage, $lang) = IkiWiki::Plugin::po::_istranslation($page);
+ next unless defined $lang && $lang eq $ll;
+
+ my $content=IkiWiki::Plugin::po::po_to_markup($page, readfile(srcfile($file)));
+ # avoid wasting space if the page is not translated at all
+ my $mastercontent=readfile(srcfile($pagesources{$masterpage}));
+ if ($content ne $mastercontent) {
+ writefile($masterpage.".".$config{default_pageext},
+ $config{destdir}, $content);
+ }
+ }
+}
msgstr ""
"Project-Id-Version: ikiwiki\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
"PO-Revision-Date: 2007-01-10 23:47+0100\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Du måste logga in först."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr ""
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
#, fuzzy
msgid "Preferences"
msgstr "Inställningar sparades."
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr ""
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Inställningar sparades."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr ""
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "diskussion"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Du är bannlyst."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "skapar %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Fel"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "redigerar %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr ""
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "Du är bannlyst."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, fuzzy, perl-format
msgid "missing %s parameter"
msgstr "mall saknar id-parameter"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "ny kanal"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "inlägg"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "ny"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "låter %s gå ut (%s dagar gammal)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "låter %s gå ut"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "behandlad ok på %s"
+msgid "last checked %s"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "kontrollerar kanalen %s ..."
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "kunde inte hitta kanalen på %s"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
#, fuzzy
msgid "feed not found"
msgstr "mallen %s hittades inte"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "kanalen kraschade XML::Feed!"
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "skapar nya sidan %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "klar"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Misslyckades med att skicka e-post"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Misslyckades med att skicka e-post"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "misslyckades med att skriva %s: %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr ""
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "Det finns inga trasiga länkar!"
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, fuzzy, perl-format
+msgid "commenting on %s"
+msgstr "skapar %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, fuzzy, perl-format
+msgid "removing old preview %s"
+msgstr "tar bort gammal sida %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "skapar %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "redigerar %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
#, fuzzy
msgid "template not specified"
msgstr "mallen %s hittades inte"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
#, fuzzy
msgid "match not specified"
msgstr "filnamn för wrapper har inte angivits"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
#, fuzzy
msgid "failed to process"
msgstr "misslyckades med att behandla mall:"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "fortune misslyckades"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+#, fuzzy
+msgid "missing page"
+msgstr "mall saknar id-parameter"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
#, fuzzy
-msgid "failed to find url in html"
-msgstr "googlecalendar misslyckades med att hitta url i html"
+msgid "not a page"
+msgstr "kan inte läsa %s: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, perl-format
+msgid "%s is an attachment, not a page."
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Måste ange %s när sökinsticket används"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
#, fuzzy
msgid "failed to run graphviz"
msgstr "linkmap misslyckades att köra dot"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+#, fuzzy
+msgid "Image::Magick is not installed"
+msgstr "polygen inte installerad"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, fuzzy, perl-format
msgid "failed to read %s: %s"
msgstr "misslyckades med att skriva %s: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, fuzzy, perl-format
msgid "failed to resize: %s"
msgstr "misslyckades med att skriva %s: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, fuzzy, perl-format
msgid "failed to determine size of image %s"
msgstr "misslyckades med att skriva %s: %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr "Måste ange url till wiki med --url när --rss eller --atom används"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+#, fuzzy
+msgid "page editing not allowed"
+msgstr "mallen %s hittades inte"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+#, fuzzy
+msgid "missing pages parameter"
+msgstr "mall saknar id-parameter"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "okänd sorteringstyp %s"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Diskussion"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "RPC::XML::Client hittades inte, pingar inte"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
#, fuzzy
msgid "failed to run dot"
msgstr "linkmap misslyckades att köra dot"
-#: ../IkiWiki/Plugin/lockedit.pm:29
-#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, fuzzy, perl-format
+msgid "%s is locked and cannot be edited"
msgstr "%s är låst av %s och kan inte redigeras"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr ""
"misslyckades med att läsa in Perl-modulen Markdown.pm (%s) eller /usr/bin/"
"markdown (%s)"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
#, fuzzy
msgid "stylesheet not found"
msgstr "mallen %s hittades inte"
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
#, fuzzy
msgid "redir page not found"
msgstr "mallen %s hittades inte"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
#, fuzzy
msgid "redir cycle is not allowed"
msgstr "mallen %s hittades inte"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Speglar"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Spegel"
msgid "more"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "getctime inte implementerad"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Skaffa ett OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "Alla sidor länkas till av andra sidor."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Kontot har skapats. Du kan nu logga in."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Fel vid skapandet av konto."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Misslyckades med att skicka e-post"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Ditt lösenord har skickats till dig via e-post."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, fuzzy, perl-format
+msgid "Will ping %s"
+msgstr "redigerar %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+#, fuzzy
+msgid "LWP not found, not pinging"
+msgstr "RPC::XML::Client hittades inte, pingar inte"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "redigerar %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "misslyckades med att kompilera %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "misslyckades med att kompilera %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "misslyckades med att kompilera %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "misslyckades med att skriva %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "misslyckades med att skriva %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "linkmap misslyckades att köra dot"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "misslyckades med att skriva %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "röst"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Antal röster:"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "polygen inte installerad"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "polygen misslyckades"
+#: ../IkiWiki/Plugin/polygen.pm:60
+#, fuzzy
+msgid "command failed"
+msgstr "fortune misslyckades"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr ""
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr ""
msgid "%A night"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:74
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, fuzzy, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s är låst av %s och kan inte redigeras"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
#, fuzzy
-msgid "missing page"
-msgstr "mall saknar id-parameter"
+msgid "no change to the file name was specified"
+msgstr "filnamn för wrapper har inte angivits"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "The page %s does not exist."
+msgid "illegal name"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:73
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Måste ange %s när sökinsticket används"
+msgid "%s already exists"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "rensar hyperestraier-sökindex"
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "uppdaterar hyperestraier-sökindex"
+#: ../IkiWiki/Plugin/rename.pm:122
+#, fuzzy, perl-format
+msgid "rename %s"
+msgstr "ritar upp %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, fuzzy, perl-format
+msgid "update for rename of %s to %s"
+msgstr "uppdatering av %s, %s av %s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
#, fuzzy
msgid "missing name or url parameter"
msgstr "genväg saknar parameter för namn eller url"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, fuzzy, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "genvägen %s pekar på %s"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
#, fuzzy
msgid "failed to parse any smileys"
msgstr "misslyckades med att tolka smilisar, inaktiverar instick"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
#, fuzzy
msgid "parse error"
msgstr "linkmap misslyckades att köra dot"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:95
+#: ../IkiWiki/Plugin/sparkline.pm:104
#, fuzzy
-msgid "bad height value"
+msgid "invalid height value"
msgstr "linkmap misslyckades att köra dot"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
#, fuzzy
msgid "missing width parameter"
msgstr "mall saknar id-parameter"
-#: ../IkiWiki/Plugin/sparkline.pm:106
+#: ../IkiWiki/Plugin/sparkline.pm:115
#, fuzzy
-msgid "bad width value"
+msgid "invalid width value"
msgstr "linkmap misslyckades att köra dot"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
#, fuzzy
msgid "failed to run php"
msgstr "linkmap misslyckades att köra dot"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, fuzzy, perl-format
msgid "parse fail at line %d: %s"
msgstr "misslyckades med att skriva %s: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
#, fuzzy
msgid "missing id parameter"
msgstr "mall saknar id-parameter"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "mallen %s hittades inte"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
#, fuzzy
msgid "failed to process:"
msgstr "misslyckades med att behandla mall:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
#, fuzzy
msgid "failed to generate image from code"
msgstr "misslyckades med att skriva %s: %s"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "getctime inte implementerad"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:85
+#, fuzzy, perl-format
+msgid "bad file name %s"
+msgstr "hoppar över felaktigt filnamn %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "hoppar över felaktigt filnamn %s"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "tar bort gammal sida %s"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "söker av %s"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "ritar upp %s"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "ritar upp %s, vilken länkar till %s"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "ritar upp %s, vilken är beroende av %s"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr "ritar upp %s, för att uppdatera dess bakåtlänkar"
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "tar bort %s, som inte längre ritas upp av %s"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: kan inte rita upp %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "kan inte läsa %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "genererar wrappers.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "bygger om wiki.."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "uppdaterar wiki.."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "klar"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "filnamn för wrapper har inte angivits"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "misslyckades med att skriva %s: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "misslyckades med att kompilera %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "generering av %s lyckades"
msgid "usage: ikiwiki [options] source dest"
msgstr "användning: ikiwiki [flaggor] källa mål"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "genererar wrappers.."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "bygger om wiki.."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "uppdaterar wiki.."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Diskussion"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr "Måste ange url till wiki med --url när --cgi används"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "Fel"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:569
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1243
+#, fuzzy, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr "%s förbehandlingsslinga detekterades på %s, djup %i"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
+#, fuzzy, perl-format
+msgid "cannot match pages: %s"
+msgstr "kan inte läsa %s: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr ""
+
+#~ msgid "discussion"
+#~ msgstr "diskussion"
+
+#~ msgid "rendering %s"
+#~ msgstr "ritar upp %s"
+
+#, fuzzy
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr "Måste ange %s när sökinsticket används"
+
+#, fuzzy
+#~ msgid "failed to find url in html"
+#~ msgstr "googlecalendar misslyckades med att hitta url i html"
+
+#~ msgid "processed ok at %s"
+#~ msgstr "behandlad ok på %s"
+
+#~ msgid "Your password has been emailed to you."
+#~ msgstr "Ditt lösenord har skickats till dig via e-post."
+
+#~ msgid "polygen failed"
+#~ msgstr "polygen misslyckades"
+
+#~ msgid "cleaning hyperestraier search index"
+#~ msgstr "rensar hyperestraier-sökindex"
+
+#~ msgid "updating hyperestraier search index"
+#~ msgstr "uppdaterar hyperestraier-sökindex"
+
#, fuzzy
#~ msgid ""
#~ "REV is not set, not running from mtn post-commit hook, cannot send "
#~ "REV är inte inställt, kör inte från svn post-commit-hook, kan inte skicka "
#~ "notifieringar"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "uppdatering av %s, %s av %s"
-
#, fuzzy
#~ msgid "%s not found"
#~ msgstr "mallen %s hittades inte"
--- /dev/null
+#!/usr/bin/perl
+# Configuration file for ikiwiki that uses the po plugin to build/update
+# po and pot files for pages in the underlays.
+
+use IkiWiki::Setup::Standard {
+ # List here all languages that have translations.
+ # Listing languages without active translations
+ # will excessively bloat things.
+ po_slave_languages => {
+ #'fr' => 'Français',
+ #'es' => 'Español',
+ #'de' => 'Deutsch',
+ 'da' => 'Dansk',
+ },
+ po_master_language => { 'code' => 'en', 'name' => 'English' },
+ po_translatable_pages => "*",
+ add_plugins => [qw{po}],
+
+ wikiname => "ikiwiki",
+ srcdir => "underlays",
+ destdir => "html",
+ templatedir => "templates",
+ # we don't want to pull in the normal underlays
+ underlaydirbase => "underlays/empty",
+ underlaydir => "underlays/empty",
+ discussion => 0,
+ locale => '',
+ verbose => 1,
+ syslog => 0,
+}
--- /dev/null
+# Danish translation of basewiki/ikiwiki page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"This wiki is powered by [ikiwiki](http://ikiwiki.info/).\n"
+"[[!if test=\"enabled(version)\"\n"
+" then=\"(Currently running version [[!version ]].)\"\n"
+"]]\n"
+msgstr ""
+"Denne wiki er drevet af [ikiwiki](http://ikiwiki.info/).\n"
+"[[!if test=\"enabled(version)\"\n"
+" then=\"(kører i øjeblikket version [[!version ]].)\"\n"
+"]]\n"
+
+#. type: Plain text
+msgid "Some documentation on using ikiwiki:"
+msgstr "Noget dokumentation om brug af ikiwiki:"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/formatting]]"
+msgstr "[[formatering|ikiwiki/formatting]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/wikilink]]"
+msgstr "[[ikiwiki/wikilink]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/subpage]]"
+msgstr "[[underside|ikiwiki/subpage]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/pagespec]]"
+msgstr "[[ikiwiki/pagespec]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/directive]]"
+msgstr "[[direktiv|ikiwiki/directive]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/markdown]]"
+msgstr "[[ikiwiki/markdown]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/openid]]"
+msgstr "[[ikiwiki/openid]]"
+
+#. type: Bullet: '* '
+msgid "[[ikiwiki/searching]]"
+msgstr "[[søgning|ikiwiki/searching]]"
--- /dev/null
+# Danish translation of basewiki/ikiwiki/blog page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This page has been removed from ikiwiki's basewiki. For documentation about "
+"creating a blog with ikiwiki, see the documentation of the [[!iki ikiwiki/"
+"directive/inline desc=inline]] directive."
+msgstr ""
+"Denne side er blevet fjernet fra ikiwiki's basewiki. For dokumentation om "
+"oprettelse af en blog med ikiwiki se dokumentationen til [[!iki ikiwiki/"
+"directive/inline desc=inline]]-direktivet."
+
+#. type: Plain text
+msgid ""
+"Please update your links, as this redirection page will be removed in a "
+"future ikiwiki release."
+msgstr ""
+"Opdatér dine henvisninger, da denne omdirigeringsside bliver fjernet i en "
+"fremtidig udgave af ikiwiki."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/directive page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Directives are similar to a [[ikiwiki/WikiLink]] in form, except they begin "
+"with `!` and may contain parameters. The general form is:"
+msgstr ""
+"Direktiver ligner et [[ikiwiki/WikiLink]] i form, undtagen at de begynder "
+"med `!` og kan indeholde parametre. Generelt er formen:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!directive param=\"value\" param=\"value\"]]\n"
+msgstr "\t\\[[!direktiv param=\"værdi\" param=\"værdi\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This gets expanded before the rest of the page is processed, and can be used "
+"to transform the page in various ways."
+msgstr ""
+"Dette udvides før resten af siden udarbejdes, og kan bruges til at omforme "
+"siden på forskellige måder."
+
+#. type: Plain text
+msgid ""
+"The quotes around values can be omitted if the value is a simple word. "
+"Also, some directives may use parameters without values, for example:"
+msgstr ""
+"Citationen omkring værdier kan udelades hvis værdien er et simpelt ord. "
+"Desuden kan nogle direktiver bruge parametre uden værdier. Eksempel:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!tag foo]]\n"
+msgstr "\t\\[[!tag foo]]\n"
+
+#. type: Plain text
+msgid ""
+"A directive does not need to all be on one line, it can be wrapped to "
+"multiple lines if you like:"
+msgstr ""
+"Et direktiv behøver ikke at blive holdt på een linje, det kan bredes ud over "
+"flere linjer hvis du har lyst:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!directive foo=\"baldersnatch\"\n"
+"\tbar=\"supercalifragilisticexpialidocious\" baz=11]]\n"
+msgstr ""
+"\t\\[[!direktiv foo=\"baldersnatch\"\n"
+"\tbar=\"supercalifragilisticexpialidocious\" baz=11]]\n"
+
+#. type: Plain text
+msgid ""
+"Also, multiple lines of *quoted* text can be used for a value. To allow "
+"quote marks inside the quoted text, delimit the block of text with triple-"
+"quotes:"
+msgstr ""
+"Flere linjer *citeret* tekst kan også bruges som værdi. For at tillade "
+"citation i den citerede tekst skal du adskille blokken med trippel-citat:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!directive text=\"\"\"\n"
+msgstr "\t\\[[!direktiv tekst=\"\"\"\n"
+
+#. type: Bullet: ' 1. '
+msgid "\"foo\""
+msgstr "\"foo\""
+
+#. type: Bullet: ' 2. '
+msgid "\"bar\""
+msgstr "\"bar\""
+
+#. type: Bullet: ' 3. '
+msgid "\"baz\""
+msgstr "\"baz\""
+
+#. type: Plain text
+msgid ""
+"ikiwiki also has an older syntax for directives, which requires a space in "
+"directives to distinguish them from [[wikilinks|ikiwiki/wikilink]]. This "
+"syntax has several disadvantages: it requires a space after directives with "
+"no parameters (such as `\\[[pagecount ]]`), and it prohibits spaces in "
+"[[wikilinks|ikiwiki/wikilink]]. ikiwiki now provides the `!`-prefixed "
+"syntax shown above as default. However, ikiwiki still supports wikis using "
+"the older syntax, if the `prefix_directives` option is disabled."
+msgstr ""
+"Ikiwiki har også en ældre syntaks til direktiver, som kræver et mellemrum i "
+"direktiver for at skelne dem fra [[wikilinks|ikiwiki/wikilink]]. Denne "
+"syntaks har flere ulemper: den kræver et mellemrum efter direktiver uden "
+"parametre (såsom `\\[[pagecount ]]`), og den forbyder mellemrum i "
+"[[wikilinks|ikiwiki/wikilink]]. Ikiwiki har nu den `!`-foranstillede syntaks "
+"vist ovenfor som det foretrukne alternativ. Ikiwiki understøtter dog fortsat "
+"den ældre syntaks, hvis ikke `prefix_directives`-valget er aktiveret."
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(listdirectives)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(listdirectives)\" then=\"\"\"\n"
+
+#. type: Plain text
+msgid "Here is a list of currently available directives in this wiki:"
+msgstr ""
+"Her er en oversigt over konkret tilgængelige direktiver i for denne wiki:"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!listdirectives ]]\n"
+msgstr "[[!listdirectives ]]\n"
--- /dev/null
+# Danish translation of basewiki/ikiwiki/formatting page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 21:25+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta title=\"Formatting wiki pages\"]]\n"
+msgstr "[[!meta title=\"Formatering af wikisider\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Text on this wiki is, by default, written in a form very close to how you "
+"might write text for an email message. This style of text formatting is "
+"called [[MarkDown]], and it works like this:"
+msgstr ""
+"Teksten på denne wiki er, som udgangspunkt, skrevet på en måde som ligger "
+"tæt op ad hvordan du muligvis formulerer dig i email-beskeder. Denne form "
+"for tekstformatering kaldes [[MarkDown]], og det fungerer sådan her:"
+
+#. type: Plain text
+msgid "Leave blank lines between paragraphs."
+msgstr "hold afstand med blanke linjer mellem afsnit."
+
+#. type: Plain text
+msgid ""
+"You can \\**emphasise*\\* or \\*\\***strongly emphasise**\\*\\* text by "
+"placing it in single or double asterisks."
+msgstr ""
+"du kan \\**fremhæve*\\* eller \\*\\***kraftigt fremhæve**\\*\\* tekst ved at "
+"placere det med enkelte eller dobbelte asterisker (stjerner) omkring."
+
+#. type: Plain text
+msgid "To create a list, start each line with an asterisk:"
+msgstr "En liste oprettes ved at begynde hver linje med en asterisk:"
+
+#. type: Bullet: '* '
+msgid "\"* this is my list\""
+msgstr "\"* dette er min liste\""
+
+#. type: Bullet: '* '
+msgid "\"* another item\""
+msgstr "\"* et andet emne\""
+
+#. type: Plain text
+msgid ""
+"To make a numbered list, start each line with a number (any number will do) "
+"followed by a period:"
+msgstr ""
+"En nummereret liste laves ved at starte hver linje med et nummer (ethvert "
+"nummer kan bruges) efterfulgt af punktum:"
+
+#. type: Bullet: '1. '
+msgid "\"1. first line\""
+msgstr "\"1. første linje\""
+
+#. type: Bullet: '2. '
+msgid "\"2. second line\""
+msgstr "\"2. anden linje\""
+
+#. type: Bullet: '2. '
+msgid "\"2. third line\""
+msgstr "\"2. tredje linje\""
+
+#. type: Plain text
+msgid ""
+"To create a header, start a line with one or more `#` characters followed by "
+"a space and the header text. The number of `#` characters controls the size "
+"of the header:"
+msgstr ""
+"En overskrift eller en sektion er en linje med et eller flere `#`-tegn "
+"efterfulgt af et mellemrum og overskriftsteksten. Antallet af `#`-tegn "
+"styrer overskriftens størrelse:"
+
+#. type: Title #
+#, no-wrap
+msgid "# h1"
+msgstr "# h1"
+
+#. type: Title ##
+#, no-wrap
+msgid "## h2"
+msgstr "## h2"
+
+#. type: Title ###
+#, no-wrap
+msgid "### h3"
+msgstr "### h3"
+
+#. type: Title ####
+#, no-wrap
+msgid "#### h4"
+msgstr "#### h4"
+
+#. type: Title #####
+#, no-wrap
+msgid "##### h5"
+msgstr "##### h5"
+
+#. type: Title ######
+#, no-wrap
+msgid "###### h6"
+msgstr "###### h6"
+
+#. type: Plain text
+msgid ""
+"To create a horizontal rule, just write three or more dashes or stars on "
+"their own line:"
+msgstr ""
+"En vandret skillelinje oprettes ved at skrive tre eller flere bindestreger "
+"eller stjerner på en linje for sig selv."
+
+#. type: Plain text
+#, no-wrap
+msgid "To quote someone, prefix the quote with \">\":\n"
+msgstr "Citater angives ved at sætte \">\" foran hver linje:\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"> To be or not to be,\n"
+"> that is the question.\n"
+msgstr ""
+"> At være eller ikke være,\n"
+"> det er spørgsmålet.\n"
+
+#. type: Plain text
+msgid "To write a code block, indent each line with a tab or 4 spaces:"
+msgstr ""
+"En kodeblok skrives ved at indrykke hver linje med eet tabulator-tegn eller "
+"4 mellemrum:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t10 PRINT \"Hello, world!\"\n"
+"\t20 GOTO 10\n"
+msgstr ""
+"\t10 PRINT \"Hello, world!\"\n"
+"\t20 GOTO 10\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"To link to an url or email address, you can just put the\n"
+"url in angle brackets: <<http://ikiwiki.info>>, or you can use the\n"
+"form \\[link text\\]\\(url\\)\n"
+msgstr ""
+"Du kan henvise til en URL eller en email-adresse ved at putte addressen i\n"
+"vinkelklammer: <<http://ikiwiki.info>>, eller du kan bruge formen\n"
+"\\[henvisningstekst\\]\\(adresse\\)\n"
+
+#. type: Plain text
+msgid ""
+"In addition to basic html formatting using [[MarkDown]], this wiki lets you "
+"use the following additional features:"
+msgstr ""
+"Udover normal html-formatering med [[MarkDown]], kan du med denne wiki bruge "
+"følgende ekstra finesser:"
+
+#. type: Bullet: '* '
+msgid ""
+"To link to another page on the wiki, place the page's name inside double "
+"square brackets. So you would use `\\[[WikiLink]]` to link to [[WikiLink]]."
+msgstr ""
+"Henvise til en anden side på wikien ved at skrive sidenavnet med dobbelte "
+"lodrette klammer omkring. Udtrykket `\\[[WikiLink]]` henviser til "
+"[[WikiLink]]."
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(smiley) and smileys\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(smiley) and smileys\" then=\"\"\"\n"
+
+#. type: Bullet: '* '
+msgid "Insert [[smileys]] and some other useful symbols. :-)"
+msgstr "Indsætte [[smileys]] og andre anvendelige symboler. :-)"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(shortcut) and shortcuts\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(shortcut) and shortcuts\" then=\"\"\"\n"
+
+#. type: Bullet: '* '
+msgid "Use [[shortcuts]] to link to common resources."
+msgstr "Bruge [[genveje|shortcuts]] til at henvise til gængse ressourcer."
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!wikipedia War\\_of\\_1812]]\n"
+msgstr "\t\\[[!wikipedia War\\_of\\_1812]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(template) and templates\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(template) and templates\" then=\"\"\"\n"
+
+#. type: Bullet: '* '
+msgid ""
+"Create and fill out [[templates]] for repeated chunks of parameterized wiki "
+"text."
+msgstr ""
+"Oprette og udfylde [[skabeloner|templates]] for gentagne klumper af "
+"parameteriseret wikitekst."
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"* Insert various [[directives|directive]] onto a page to perform useful\n"
+" actions.\n"
+"[[!if test=\"enabled(toc) or enabled(meta) or enabled(inline)\" then=\"\"\"\n"
+msgstr ""
+"* Indsæt diverse [[directiver|directive]] på en side for at udføre nyttige\n"
+" handlinger.\n"
+"[[!if test=\"enabled(toc) or enabled(meta) or enabled(inline)\" then=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid " For example, you can:\n"
+msgstr " Eksempelvis kan du:\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(toc)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(toc)\" then=\"\"\"\n"
+
+#. type: Bullet: ' * '
+msgid "Add a table of contents to a page:"
+msgstr "Tilføje en indholdsfortegnelse til en side:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!toc]]\n"
+msgstr "\t\\[[!toc]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(meta)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(meta)\" then=\"\"\"\n"
+
+#. type: Bullet: ' * '
+msgid "Change the title of a page:"
+msgstr "Ændre titlen på en side:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!meta title=\"full page title\"]]\n"
+msgstr "\t\\[[!meta title=\"fuldstændige sidetitel\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(inline)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(inline)\" then=\"\"\"\n"
+
+#. type: Bullet: ' * '
+msgid "Create a blog by inlining a set of pages:"
+msgstr "Oprette en [[blog]] ved at indlejre et udvalg af sider:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"blog/*\"]]\n"
+msgstr "\t\\[[!inline pages=\"blog/*\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(listdirectives)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(listdirectives)\" then=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid " Full list of [[directives|directive]] enabled for this wiki:\n"
+msgstr " Komplet oversigt over [[directiver|directive]] aktiveret for denne wiki:\n"
+
+#. type: Plain text
+#, no-wrap
+msgid " [[!listdirectives ]]\n"
+msgstr " [[!listdirectives ]]\n"
--- /dev/null
+# Danish translation of basewiki/ikiwiki/markdown page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"[Markdown](http://daringfireball.net/projects/markdown/) is a minimal "
+"markup language that resembles plain text as used in email messages. It is "
+"the markup language used by this wiki by default."
+msgstr ""
+"[Markdown](http://daringfireball.net/projects/markdown/) er et minimalt "
+"opmærkningssprog som afspejler simpel tekst som det bruges i email-beskeder. "
+"Det er standard opmærkningssprog for denne wiki."
+
+#. type: Plain text
+msgid ""
+"For documentation about the markdown syntax, see [[formatting]] and "
+"[Markdown: syntax](http://daringfireball.net/projects/markdown/syntax)."
+msgstr ""
+"Du kan læse dokumentation til markdown-syntaksen under [[formatering|"
+"formatting]] og [Markdown: syntax](http://daringfireball.net/projects/"
+"markdown/syntax)."
+
+#. type: Plain text
+msgid ""
+"Note that [[WikiLinks|WikiLink]] and [[directives|directive]] are not part "
+"of the markdown syntax, and are the only bit of markup that this wiki "
+"handles internally."
+msgstr ""
+"Bemærk at [[WikiLinks|WikiLink]] og [[direktiver|directive]] ikke er en del "
+"af markdown-syntaksen, og er de eneste stumper opmærkning som denne wiki "
+"håndterer internt."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/openid page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta title=\"OpenID\"]]\n"
+msgstr "[[!meta title=\"OpenID\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!if test=\"enabled(openid)\"\n"
+" then=\"This wiki has OpenID **enabled**.\"\n"
+" else=\"This wiki has OpenID **disabled**.\"]]\n"
+msgstr ""
+"[[!if test=\"enabled(openid)\"\n"
+" then=\"Denne wiki har OpenID **aktiveret**.\"\n"
+" else=\"Denne wiki har OpenID **deaktiveret**.\"]]\n"
+
+#. type: Plain text
+msgid ""
+"[OpenID](http://openid.net) is a decentralized authentication mechanism that "
+"allows you to have one login that you can use on a growing number of "
+"websites."
+msgstr ""
+"[OpenID](http://openid.net) er en decentral ægthedsmekanisme som giver dig "
+"mulighed for at have eet login som du kan bruge på et voksende antal "
+"websteder."
+
+#. type: Plain text
+msgid ""
+"To sign up for an OpenID, visit one of the following identity providers:"
+msgstr ""
+"Du kan registrere en OpenID ved at besøge en af de følgende "
+"identitetsudbydere:"
+
+#. type: Bullet: '* '
+msgid "[MyOpenID](https://www.myopenid.com/)"
+msgstr "[MyOpenID](https://www.myopenid.com/)"
+
+#. type: Bullet: '* '
+msgid "[GetOpenID](https://getopenid.com/)"
+msgstr "[GetOpenID](https://getopenid.com/)"
+
+#. type: Bullet: '* '
+msgid "[Videntity](http://videntity.org/)"
+msgstr "[Videntity](http://videntity.org/)"
+
+#. type: Bullet: '* '
+msgid "[LiveJournal](http://www.livejournal.com/openid/)"
+msgstr "[LiveJournal](http://www.livejournal.com/openid/)"
+
+#. type: Bullet: '* '
+msgid "[TrustBearer](https://openid.trustbearer.com/)"
+msgstr "[TrustBearer](https://openid.trustbearer.com/)"
+
+#. type: Bullet: '* '
+msgid ""
+"or any of the [many others out there](http://openiddirectory.com/openid-"
+"providers-c-1.html)"
+msgstr ""
+"eller enhver af de [mange andre derude](http://openiddirectory.com/openid-"
+"providers-c-1.html)"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"Your OpenID is the URL that you are given when you sign up.\n"
+"[[!if test=\"enabled(openid)\" then=\"\"\"\n"
+msgstr ""
+"Din OpenID er den URL som du får når du registrerer dig.\n"
+"[[!if test=\"enabled(openid)\" then=\"\"\"\n"
+
+#. type: Plain text
+msgid ""
+"To sign in to this wiki using OpenID, just enter it in the OpenID field in "
+"the signin form. You do not need to give this wiki a password or go through "
+"any registration process when using OpenID."
+msgstr ""
+"Du kan logge på denne wiki med OpenID, ved blot at angive den i OpenID-"
+"feltet på login-siden. Du behøves ikke at oplyse din adgangskode til denne "
+"wiki eller at gennemgå en registreringsproces når du bruger OpenID."
+
+#. type: Plain text
+msgid ""
+"It's also possible to make a page in the wiki usable as an OpenID url, by "
+"delegating it to an openid server. Here's an example of how to do that:"
+msgstr ""
+"Det er også muligt at lave en side i wikien brugbar som en OpenID URL, ved "
+"at delegere den til en openid server. Her er et eksempel på hvordan det kan "
+"gøres:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!meta openid=\"http://yourid.myopenid.com/\"\n"
+"\t server=\"http://www.myopenid.com/server\"]]\n"
+msgstr ""
+"\t\\[[!meta openid=\"http://yourid.myopenid.com/\"\n"
+"\t server=\"http://www.myopenid.com/server\"]]\n"
--- /dev/null
+# Danish translation of basewiki/ikiwiki/pagespec page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"To select a set of pages, such as pages that are locked, pages whose commit "
+"emails you want subscribe to, or pages to combine into a blog, the wiki uses "
+"a PageSpec. This is an expression that matches a set of pages."
+msgstr ""
+"Til at angive et udvalg af sider, eksempelvis låste sider, sider du vil "
+"abonnere på ændringer til, eller sider som skal udgøre en blog, anvender "
+"wikien et PageSpec. dette er et udtryk som passer for et bestemt udvalg af "
+"sider."
+
+#. type: Plain text
+msgid ""
+"The simplest PageSpec is a simple list of pages. For example, this matches "
+"any of the three listed pages:"
+msgstr ""
+"Det simpleste PageSpec er simpelthen en opremsning af sider med \"or\" "
+"imellem (\"or\" betyder \"eller\" på engelsk). Dette passer eksempelvis for "
+"enhver af de tre nævnte sider:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\tfoo or bar or baz\n"
+msgstr "\tfoo or bar or baz\n"
+
+#. type: Plain text
+msgid ""
+"More often you will want to match any pages that have a particular thing in "
+"their name. You can do this using a glob pattern. \"`*`\" stands for any "
+"part of a page name, and \"`?`\" for any single letter of a page name. So "
+"this matches all pages about music, and any [[SubPage]]s of the SandBox, but "
+"does not match the SandBox itself:"
+msgstr ""
+"Mere hyppigt har du dog brug for at passe for sider med noget bestemt i "
+"deres navne. Dette kan du udtrykke med et \"glob-mønster\". \"`*`\" står "
+"for enhver del af et sidenavn, og \"`?`\" for ethvert enkeltbogstav i et "
+"sidenavn. Så dette passer for alle sider om musik, og alle [[UnderSider||"
+"SubPage]] til sandkassen, men ikke selve sandkasse-siden:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t*music* or SandBox/*\n"
+msgstr "\t*musik* or SandBox/*\n"
+
+#. type: Plain text
+msgid ""
+"You can also prefix an item with \"`!`\" to skip pages that match it. So to "
+"match all pages except for Discussion pages and the SandBox:"
+msgstr ""
+"Du kan også angive \"`!`\" foran et emne for at undgå sider som passer for "
+"det. Så for at passe for alle sider undtagen diskussionssider og sandkassen:"
+
+#. type: Bullet: ' * '
+msgid "and !SandBox and !*/Discussion"
+msgstr "and !SandBox and !*/Discussion"
+
+#. type: Plain text
+msgid ""
+"Some more elaborate limits can be added to what matches using these "
+"functions:"
+msgstr "Resultaterne kan begrænses mere nuanceret med disse funktioner:"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`link(page)`\" - matches only pages that link to a given page (or glob)"
+msgstr ""
+"\"`link(side)`\" - passer kun for sider som henviser til en given side "
+"(eller glob)"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`tagged(tag)`\" - matches pages that are tagged or link to the given tag "
+"(or tags matched by a glob)"
+msgstr ""
+"\"`tagged(mærkat)`\" - passer for sider mærket af med eller som henviser til "
+"den givne mærkat (eller mærkater som passer for et glob)"
+
+#. type: Bullet: '* '
+msgid "\"`backlink(page)`\" - matches only pages that a given page links to"
+msgstr ""
+"\"`backlink(side)`\" - passer kun for sider som en given side henviser til"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`creation_month(month)`\" - matches only pages created on the given month"
+msgstr ""
+"\"`creation_month(måned)`\" - passer kun for sider oprettet den givne måned"
+
+#. type: Bullet: '* '
+msgid "\"`creation_day(mday)`\" - or day of the month"
+msgstr "\"`creation_day(månedsdag)`\" - eller dag på måneden"
+
+#. type: Bullet: '* '
+msgid "\"`creation_year(year)`\" - or year"
+msgstr "\"`creation_year(år)`\" - eller år"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`created_after(page)`\" - matches only pages created after the given page "
+"was created"
+msgstr ""
+"\"`created_after(side)`\" - passer kun for sider oprettet efter den givne "
+"side blev oprettet"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`created_before(page)`\" - matches only pages created before the given "
+"page was created"
+msgstr ""
+"\"`created_before(side)`\" - passer kun for sider oprettet før den givne "
+"side blev oprettet"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`glob(someglob)`\" - matches pages that match the given glob. Just writing "
+"the glob by itself is actually a shorthand for this function."
+msgstr ""
+"\"`glob(nogetglob)`\" - passer for sider som passer for det givne glob. Blot "
+"at skrive glob'et alene er faktisk en genvej til denne funktion."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`internal(glob)`\" - like `glob()`, but matches even internal-use pages "
+"that globs do not usually match."
+msgstr ""
+"\"`internal(glob)`\" - lissom `glob()`, men passer også for internt anvendte "
+"sider som glob normalt ikke passer for."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`title(glob)`\", \"`author(glob)`\", \"`authorurl(glob)`\", \"`license"
+"(glob)`\", \"`copyright(glob)`\" - match pages that have the given metadata, "
+"matching the specified glob."
+msgstr ""
+"\"`title(glob)`\", \"`author(glob)`\", \"`authorurl(glob)`\", \"`license"
+"(glob)`\", \"`copyright(glob)`\" - passer for sider med de givne metadata, "
+"som passer for det angivne glob."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`user(username)`\" - tests whether a modification is being made by a user "
+"with the specified username. If openid is enabled, an openid can also be put "
+"here."
+msgstr ""
+"\"`user(brugernavn)`\" - tester hvorvidt en ændring foretages af en bruger "
+"med det angivne brugernavn. Hvis openid er aktiveret, kan en openid også "
+"bruges her."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`admin()`\" - tests whether a modification is being made by one of the "
+"wiki admins."
+msgstr ""
+"\"`admin()`\" - tester hvorvidt en ændring foretages af en af wiki-"
+"administratorerne."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`ip(address)`\" - tests whether a modification is being made from the "
+"specified IP address."
+msgstr ""
+"\"`ip(adresse)`\" - tester hvorvidt en ændring foretages fra den angivne IP-"
+"adresse."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`postcomment(glob)`\" - matches only when comments are being posted to a "
+"page matching the specified glob"
+msgstr ""
+"\"`postcomment(glob)`\" - passer kun når kommentarer er blevet indsendt "
+"til en side som passer for det angivne glob"
+
+#. type: Plain text
+msgid ""
+"For example, to match all pages in a blog that link to the page about music "
+"and were written in 2005:"
+msgstr ""
+"For eksempelvis at passe for alle sider i en blog som henviser til en side "
+"om musik og som blev skrevet i 2005:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\tblog/* and link(music) and creation_year(2005)\n"
+msgstr "\tblog/* and link(musik) and creation_year(2005)\n"
+
+#. type: Plain text
+msgid ""
+"Note the use of \"and\" in the above example, that means that only pages "
+"that match each of the three expressions match the whole. Use \"and\" when "
+"you want to combine expression like that; \"or\" when it's enough for a page "
+"to match one expression. Note that it doesn't make sense to say \"index and "
+"SandBox\", since no page can match both expressions."
+msgstr ""
+"Bemærk brugen af \"and\" i eksemplet ovenfor (\"and\" betyder \"og\" på "
+"engelsk), som betyder at kun sider der passer for hvert af de tre udtryk "
+"passer for det hele. Brug \"and\" når du vil kombinere udtryk på den måde; "
+"\"or\" når det er nok for en side at den passer for ét udtryk. Bemærk at det "
+"ikke giver mening at sige \"index and SandBox\", da ingen sider kan passe "
+"for begge udtryk."
+
+#. type: Plain text
+msgid ""
+"More complex expressions can also be created, by using parentheses for "
+"grouping. For example, to match pages in a blog that are tagged with either "
+"of two tags, use:"
+msgstr ""
+"Mere komplekse udtryk kan dannes ved at gruppere med paranteser. Eksempelvis "
+"passer dette for sider i en blog som er mærket af med en af to mærkater:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\tblog/* and (tagged(foo) or tagged(bar))\n"
+msgstr "\tblog/* and (tagged(foo) or tagged(bar))\n"
+
+#. type: Plain text
+msgid ""
+"Note that page names in PageSpecs are matched against the absolute filenames "
+"of the pages in the wiki, so a pagespec \"foo\" used on page \"a/b\" will "
+"not match a page named \"a/foo\" or \"a/b/foo\". To match relative to the "
+"directory of the page containing the pagespec, you can use \"./\". For "
+"example, \"./foo\" on page \"a/b\" matches page \"a/foo\"."
+msgstr ""
+"Bemærk at PageSpecs for sidenavne afstemmes som de absolutte filnavne for "
+"siderne i wikien, så et pagespec \"foo\" brugt på siden \"a/b\" vil ikke "
+"passe for siderne navngivet \"a/foo\" eller \"a/b/foo\". For at afstemme "
+"relativt til samme mappe som siden der indeholder pagespec'et kan du bruge "
+"\"./\". Eksempelvis passer \"./foo\" på siden \"a/b\" for siden \"a/foo\"."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/pagespec/attachment page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!if test=\"enabled(attachment)\"\n"
+" then=\"This wiki has attachments **enabled**.\"\n"
+" else=\"This wiki has attachments **disabled**.\"]]\n"
+msgstr ""
+"[[!if test=\"enabled(attachment)\"\n"
+" then=\"Denne wiki har vedhæftninger **aktiveret**.\"\n"
+" else=\"Denne wiki har vedhæftninger **deaktiveret**.\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If attachments are enabled, the wiki admin can control what types of "
+"attachments will be accepted, via the `allowed_attachments` configuration "
+"setting."
+msgstr ""
+"Hvis vedhæftninger er aktiveret, kan wiki-administratoren styre hvilke typer "
+"vedhæftninger der vil blive accepteret gennem opsætningsindstillingen "
+"`allowed_attachments`."
+
+#. type: Plain text
+msgid ""
+"For example, to limit arbitrary files to 50 kilobytes, but allow larger mp3 "
+"files to be uploaded by joey into a specific directory, and check all "
+"attachments for viruses, something like this could be used:"
+msgstr ""
+"Som eksempel, for at begrænse vilkårlige filer til 50 kilobytes, men tillade "
+"større mp3-filer at blive lagt op af joey til en bestemt mappe, og checke "
+"alle vedhæftninger for vira, kunne noget i stil med dette bruges:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\tvirusfree() and ((user(joey) and podcast/*.mp3 and mimetype(audio/mpeg) and maxsize(15mb)) or (!ispage() and maxsize(50kb)))\n"
+msgstr "\tvirusfree() and ((user(joey) and podcast/*.mp3 and mimetype(audio/mpeg) and maxsize(15mb)) or (!ispage() and maxsize(50kb)))\n"
+
+#. type: Plain text
+msgid ""
+"The regular [[ikiwiki/PageSpec]] syntax is expanded with the following "
+"additional tests:"
+msgstr ""
+"Den normale [[ikiwiki/PageSpec]]-syntaks er udvidet med følgende yderligere "
+"tests:"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`maxsize(size)`\" - tests whether the attachment is no larger than the "
+"specified size. The size defaults to being in bytes, but \"kb\", \"mb\", \"gb"
+"\" etc can be used to specify the units."
+msgstr ""
+"\"`maxsize(størrelse)`\" - tester hvorvidt vedhæftningen højst fylder den "
+"angivne størrelse. Størrelsen angives som standard i bytes, men \"kb\", \"mb"
+"\", \"gb\" osv. kan bruges til at angive enheder."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`minsize(size)`\" - tests whether the attachment is no smaller than the "
+"specified size."
+msgstr ""
+"\"`minsize(størrelse)`\" - tester hvorvidt størrelsen mindst fylder den "
+"angivne størrelse."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`ispage()`\" - tests whether the attachment will be treated by ikiwiki as "
+"a wiki page. (Ie, if it has an extension of \".mdwn\", or of any other "
+"enabled page format)."
+msgstr ""
+"\"`ispage()`\" - tester hvorvidt vedhæftningen bliver håndteret af ikiwiki "
+"som en wikiside. (altså om den har endelsen \".mdwn\", eller et hvilket som "
+"helst andet aktiveret sideformat)."
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" So, if you don't want to allow wiki pages to be uploaded as attachments,\n"
+" use `!ispage()` ; if you only want to allow wiki pages to be uploaded\n"
+" as attachments, use `ispage()`.\n"
+msgstr ""
+" Derfor, hvis du ikke vil tillade wikisider at blive lagt op som vedhæftninger,\n"
+" så brug `!ispage()` ; hvis du kun vil tillade wikisider at blive lagt op som\n"
+" vedhæftninger, så brug `ispage()`.\n"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`mimetype(foo/bar)`\" - checks the MIME type of the attachment. You can "
+"include a glob in the type, for example `mimetype(image/*)`."
+msgstr ""
+"\"`mimetype(foo/bar)`\" - checker MIME-typen for vedhæftningen. Du kan "
+"angive et glob som type, eksampelvis `mimetype(image/*)`."
+
+#. type: Bullet: '* '
+msgid "\"`virusfree()`\" - checks the attachment with an antiviral program."
+msgstr "\"`virusfree()`\" - checker vedhæftningen med et antivirusprogram."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/pagespec/po page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-20 11:33+0300\n"
+"PO-Revision-Date: 2009-07-20 11:41+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!if test=\"enabled(po)\"\n"
+" then=\"This wiki has po support **enabled**.\"\n"
+" else=\"This wiki has po support **disabled**.\"]]\n"
+msgstr ""
+"[[!if test=\"enabled(po)\"\n"
+" then=\"Denne wiki har oversættelser **aktiveret**.\"\n"
+" else=\"Denne wiki har oversættelser **deaktiveret**.\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If the [[!iki plugins/po desc=po]] plugin is enabled, the regular [[ikiwiki/"
+"PageSpec]] syntax is expanded with the following additional tests that can "
+"be used to improve user navigation in a multi-lingual wiki:"
+msgstr ""
+"Hvis udvidelsen [[!iki plugins/po desc=po]] er aktiveret er den normale "
+"[[ikiwiki/PageSpec]]-syntaks udvidet med følgende yderligere tests som kan "
+"bruges til at forbedre brugernavigation i en flersproget wiki:"
+
+#. type: Bullet: '* '
+msgid ""
+"\"`lang(LL)`\" - tests whether a page is written in the language specified "
+"as a ISO639-1 (two-letter) language code."
+msgstr ""
+"\"`lang(LL)`\" - tester hvorvidt en side er skrevet i sproget angivet som en "
+"ISO639-1 (to-bogstavs) sprogkode."
+
+#. type: Bullet: '* '
+msgid ""
+"\"`currentlang()`\" - tests whether a page is written in the same language "
+"as the current page."
+msgstr ""
+"\"`currentlang()`\" - tester hvorvidt en side er skrevet i samme sprog som "
+"den nuværende side."
+
+#. type: Plain text
+msgid ""
+"Note that every non-po page is considered to be written in "
+"`po_master_language`, as specified in `ikiwiki.setup`."
+msgstr ""
+"Bemærk at enhver ikke-po side antages at være skrevet i "
+"`po_master_language`, som angivet i `ikiwiki.setup`."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/preprocessordirective page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta redir=ikiwiki/directive delay=10]]\n"
+msgstr "[[!meta redir=ikiwiki/directive delay=10]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This page has moved to [[ikiwiki/directive|ikiwiki/directive]]. Please "
+"update your links, as this redirection page will be removed in a future "
+"ikiwiki release."
+msgstr ""
+"Denne side er flyttet til [[ikiwiki/directive|ikiwiki/directive]]. Opdatér "
+"dine henvisninger, da denne omdirigeringsside bliver fjernet i en fremtidig "
+"udgave af ikiwiki."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/searching page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!if test=\"enabled(search)\"\n"
+"then=\"This wiki has searching **enabled**.\"\n"
+"else=\"This wiki has searching **disabled**.\"]]\n"
+msgstr ""
+"[[!if test=\"enabled(search)\"\n"
+"then=\"Denne wiki har søgning **aktiveret**.\"\n"
+"else=\"Denne wiki har søgning **deaktiveret**.\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If searching is enabled, you can enter search terms in the search field, as "
+"you'd expect. There are a few special things you can do to constuct more "
+"powerful searches."
+msgstr ""
+"Hvis søgning er aktiveret, kan du angive søgeudtryk i søgefeltet, som du "
+"ville forvente. Der er et par specielle ting du kan gøre for at konstruere "
+"mere effektive søgninger."
+
+#. type: Bullet: '* '
+msgid "To match a phrase, enclose it in double quotes."
+msgstr ""
+"Put gåseøjne omkring nogle ord for at søge efter dem som én formulering."
+
+#. type: Bullet: '* '
+msgid "`AND` can be used to search for documents containing two expressions."
+msgstr ""
+"`AND` kan bruges til at søge efter dokumenter som indeholder to udtryk."
+
+#. type: Bullet: '* '
+msgid ""
+"`OR` can be used to search for documents containing either one of two "
+"expressions."
+msgstr ""
+"`OR` kan bruges ti at søge efter dokumenter som indeholder ethvert af to "
+"udtryk."
+
+#. type: Bullet: '* '
+msgid ""
+"Parentheses can be used to build up complicated search expressions. For "
+"example, \"(foo AND bar) OR (me AND you)\""
+msgstr ""
+"Parenteser kan bruges til at opbygge komplicerede søgeformuleringer. "
+"Eksempelvis \"(foo AND bar) OR (mig AND dig)\""
+
+#. type: Bullet: '* '
+msgid ""
+"Prefix a search term with \"-\" to avoid it from appearing in the results. "
+"For example, \"-discussion\" will omit \"discussion\"."
+msgstr ""
+"Put \"-\" foran et søgeudtryk for at undgå det blandt resultaterne. "
+"Eksempelvis vil \"-discussion\" udelade \"discussion\"."
+
+#. type: Bullet: '* '
+msgid "To search for a page with a given title, use \"title:foo\"."
+msgstr "Brug \"title:foo\" til at søge efter en side med en given titel."
+
+#. type: Bullet: '* '
+msgid "To search for pages that contain a \"bar\" link, use \"link:bar\"."
+msgstr ""
+"Brug \"link:bar\" til at søge efter sider som indeholder henvisning til \"bar"
+"\"."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/subpage page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"ikiwiki supports placing pages in a directory hierarchy. For example, this "
+"page, [[SubPage]] has some related pages placed under it, like [[SubPage/"
+"LinkingRules]]. This is a useful way to add some order to your wiki rather "
+"than just having a great big directory full of pages."
+msgstr ""
+"ikiwiki understøtter placering af sider i et mappehierarki. Eksempelvis har "
+"denne side, [[UnderSide|SubPage]], nogle relaterede sider placeret under "
+"sig, bl.a. [[HenvisningsRegler|SubPage/LinkingRules]]. dette er en praktisk "
+"måde at bringe orden i din wiki fremfor blot at have een stor mappe fuld af "
+"sider."
+
+#. type: Plain text
+msgid ""
+"To add a SubPage, just make a subdirectory and put pages in it. For example, "
+"this page is SubPage.mdwn in this wiki's source, and there is also a SubPage "
+"subdirectory, which contains SubPage/LinkingRules.mdwn. Subpages can be "
+"nested as deeply as you'd like."
+msgstr ""
+"En [[UnderSide|SubPage]] oprettes ved blot at oprette undermappen og tilføje "
+"sider til den. Denne side er eksempelvis SubPage.mdwn i kildekoden til denne "
+"wiki, og der er også en SubPage undermappe, som indeholder SubPage/"
+"LinkingRules.mdwn. Undersider kan nedarves så dybt du har lyst."
+
+#. type: Plain text
+msgid "Linking to and from a SubPage is explained in [[LinkingRules]]."
+msgstr ""
+"Henvisninger til og fra en [[UnderSide||SubPage]] er forklaret under "
+"[[HenvisningsRegler||LinkingRules]]."
--- /dev/null
+# Danish translation of basewiki/ikiwiki/subpage/linkingrules page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"To link to or from a [[SubPage]], you can normally use a regular "
+"[[WikiLink]] that does not contain the name of the parent directory of the "
+"[[SubPage]]. Ikiwiki descends the directory hierarchy looking for a page "
+"that matches your link."
+msgstr ""
+"For at henvise til eller fra en [[underside|SubPage]] kan du normalt bruge "
+"en almindelig normal [[WikiLink]] som ikke indeholder navnet på den "
+"overliggende mappe til [[undersiden|SubPage]]. Ikiwiki gennemgår "
+"mappehierarkiet og kigger efter en side som passer til din henvisning."
+
+#. type: Plain text
+msgid ""
+"For example, if FooBar/SubPage links to \"OtherPage\", ikiwiki will first "
+"prefer pointing the link to FooBar/SubPage/OtherPage if it exists, next to "
+"FooBar/OtherPage and finally to OtherPage in the root of the wiki."
+msgstr ""
+"Hvis eksempelvis FooBar/UnderSide henviser til \"EnAndenSide\", vil ikiwiki "
+"først foretrække at knytte henvisningen til FooBar/UnderSide/EnAndenSide "
+"hvis den eksisterer, så til FooBar/EnAndenSide og til sidst til EnAndenSide "
+"i roden af wikien."
+
+#. type: Plain text
+msgid ""
+"Note that this means that if a link on FooBar/SomePage to \"OtherPage\" "
+"currently links to OtherPage, in the root of the wiki, and FooBar/OtherPage "
+"is created, the link will _change_ to point to FooBar/OtherPage. On the "
+"other hand, a link from BazBar to \"OtherPage\" would be unchanged by this "
+"creation of a [[SubPage]] of FooBar."
+msgstr ""
+"Bemærk at dette betyder, at hvis en henvisning fra FooBar/EnSide til "
+"\"EnAndenSide\" i øjeblikket henviser til EnAndenSide i roden af wikien, og "
+"FooBar/EnAndenSide oprettes, så vil henvisningen blive _ændret_ til at pege "
+"på FooBar/EnAndenSide. Omvendt vil en henvisning fra BazBar til \"EnAndenSide"
+"\" ikke blive berørt af oprettelsen af en [[underside|SubPage]] til FooBar."
+
+#. type: Plain text
+msgid ""
+"You can also specify a link that contains a directory name, like \"FooBar/"
+"OtherPage\" to more exactly specify what page to link to. This is the only "
+"way to link to an unrelated [[SubPage]]."
+msgstr ""
+"Du kan også angive en henvisning som indeholder et mappenavn, lissom "
+"\"FooBar/EnAndenSide\", for mere nøjagtigt at angive hvilken side der "
+"henvises til. Kun på den måde kan du henvise til en anden sides [[underside|"
+"SubPage]]."
+
+#. type: Plain text
+msgid ""
+"You can use this to, for example, to link from BazBar to \"FooBar/SubPage\", "
+"or from BazBar/SubPage to \"FooBar/SubPage\"."
+msgstr ""
+"Du kan bruge dette til eksempelvis at henvise fra BazBar til \"FooBar/"
+"UnderSide\", eller fra BazBar/UnderSide til \"FooBar/UnderSide\"."
+
+#. type: Plain text
+msgid ""
+"You can also use \"/\" at the start of a link, to specify exactly which page "
+"to link to, when there are multiple pages with similar names and the link "
+"goes to the wrong page by default. For example, linking from \"FooBar/SubPage"
+"\" to \"/OtherPage\" will link to the \"OtherPage\" in the root of the wiki, "
+"even if there is a \"FooBar/OtherPage\"."
+msgstr ""
+"Du kan også bruge \"/\" i begyndelsen af en henvisning, til at angive "
+"nøjagtigt hvilken side der henvises til, når der er flere mulige sider med "
+"lignende navne og henvisningen ender forkert som standard. Eksempelvis vil "
+"en henvisning fra \"FooBar/UnderSide\" til \"/EnAndenSide\" henvise til "
+"\"EnAndenSide\" i roden af wikien, selvom der er en \"FooBar/EnAndenSide\"."
+
+#. type: Plain text
+msgid ""
+"Also, if the wiki is configured with a userdir, you can link to pages within "
+"the userdir without specifying a path to them. This is to allow for easy "
+"linking to a user's page in the userdir, to sign a comment. These links are "
+"checked for last of all."
+msgstr ""
+"Desuden kan du, hvis wikien er opsat med \"userdir\", henvise til sider "
+"under hjemmemapper uden at angive en sti til dem. Dette er for at tillade "
+"enkel henvisning til en brugers side i hjemmemappen, som signatur ved en "
+"kommentar. Sådanne henvisninger prøves allersidst."
--- /dev/null
+# Danish translation of wikilink page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"WikiLinks provide easy linking between pages of the wiki. To create a "
+"[[WikiLink]], just put the name of the page to link to in double brackets. "
+"For example `\\[[WikiLink]]`."
+msgstr ""
+"WikiLinks gør det muligt enkelt at lave henvisninger (linke) mellem sider i\n"
+"wikien. Opret en [[WikiLink]] ved at skrive siden du vil henvise til med\n"
+"dobbelte klammer omkring. Ekempelvis `\\[[WikiLink]]`.\n"
+
+#. type: Plain text
+msgid ""
+"If you ever need to write something like `\\[[WikiLink]]` without creating a "
+"wikilink, just prefix it with a `\\`, like `\\\\[[WikiLink]]`."
+msgstr ""
+"Hvis du vil skrive noget i stil med `\\[[WikiLink]]` uden at det skal blive "
+"til en wikilink, så put en `\\` (backslash) foran, som i `\\\\[[WikiLink]]`."
+
+#. type: Plain text
+msgid ""
+"There are some special [[SubPage/LinkingRules]] that come into play when "
+"linking between [[SubPages|SubPage]]."
+msgstr ""
+"Specielle [[henvisningsregler|SubPage/LinkingRules]] træder i kraft når der "
+"henvises på tværs af [[undersider|SubPage]]."
+
+#. type: Plain text
+msgid ""
+"Also, if the file linked to by a WikiLink looks like an image, it will be "
+"displayed inline on the page."
+msgstr ""
+"Desuden, hvis filen der henvises til med en WikiLink ligner et billede, vil "
+"det blive vist indlejret i siden."
+
+#. type: Plain text
+msgid ""
+"WikiLinks are matched with page names in a case-insensitive manner, so you "
+"don't need to worry about getting the case the same, and can capitalise "
+"links at the start of a sentence, and so on."
+msgstr ""
+"WikiLinks knyttes til sidenavne uden skelen til store og små bogstaver, så "
+"du behøver ikke at bekymre dig om dette, og kan anvende stort "
+"begyndelsesbogstav i begyndelsen af en sætning o.l."
+
+#. type: Plain text
+msgid ""
+"It's also possible to write a WikiLink that uses something other than the "
+"page name as the link text. For example `\\[[foo_bar|SandBox]]` links to the "
+"SandBox page, but the link will appear like this: [[foo_bar|SandBox]]."
+msgstr ""
+"Det er også muligt at skrive en WikiLink som bruger noget andet end "
+"sidenavnet som henvisningstekst. Eksempelvis henviser `\\[[foo_bar|SandBox]]"
+"` til sandkassen, men henvisningen fremstår som her: [[foo_bar|SandBox]]."
+
+#. type: Plain text
+msgid ""
+"To link to an anchor inside a page, you can use something like `"
+"\\[[WikiLink#foo]]` ."
+msgstr ""
+"For at henvise til et anker inde på en side, kan du bruge noget i stil med `"
+"\\[[WikiLink#foo]]` ."
+
+#. type: Title ##
+#, no-wrap
+msgid "Directives and WikiLinks"
+msgstr "Direktiver og wikilinks"
+
+#. type: Plain text
+msgid ""
+"ikiwiki has two syntaxes for [[directives|directive]]. The older syntax "
+"used spaces to distinguish between directives and wikilinks; as a result, "
+"with that syntax in use, you cannot use spaces in WikiLinks, and must "
+"replace spaces with underscores. The newer syntax, enabled with the "
+"`prefix_directives` option in an ikiwiki setup file, prefixes directives "
+"with `!`, and thus does not prevent links with spaces. Future versions of "
+"ikiwiki will turn this option on by default."
+msgstr ""
+"ikiwiki har to syntakser til [[direktiver|directive]]. Den ældre syntaks "
+"brugte mellemrum til at skelne mellem direktiver og wikilinks; det medfører, "
+"at når den syntaks anvendes kan du ikke bruge mellemrum i WikiLinks, og må "
+"erstatte mellemrum med understregning. Den nyere syntaks, aktiveret med "
+"valget `prefix_directives` i en ikiwiki-opsætningsfil, sætter `!` foran "
+"direktiver, og forhindrer derfor ikke henvisninger med mellemrum. Fremtidige "
+"versioner af ikiwiki vil aktivere dette valg som standard."
--- /dev/null
+# Danish translation of basewiki/index page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid "Welcome to your new wiki."
+msgstr "Velkommen til din nye wiki."
+
+#. type: Plain text
+msgid "All wikis are supposed to have a [[SandBox]], so this one does too."
+msgstr ""
+"Alle wikier forventes at have en [[SandKasse|SandBox]], så det har denne "
+"også."
+
+#. type: Plain text
+msgid "This wiki is powered by [ikiwiki](http://ikiwiki.info/)."
+msgstr "Denne wiki er drevet af [ikiwiki](http://ikiwiki.info/)."
--- /dev/null
+# Danish translation of basewiki/recentchanges page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(meta)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(meta)\" then=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta title=\"RecentChanges\"]]\n"
+msgstr "[[!meta title=\"SenesteÆndringer\"]]\n"
+
+#. type: Plain text
+msgid "Recent changes to this wiki:"
+msgstr "Seneste ændringer til denne wiki:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!inline pages=\"internal(recentchanges/change_*) and !*/Discussion\" \n"
+"template=recentchanges show=0]]\n"
+msgstr ""
+"[[!inline pages=\"internal(recentchanges/change_*) and !*/Discussion\" \n"
+"template=recentchanges show=0]]\n"
--- /dev/null
+# Danish translation of basewiki/sandbox page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"This is the SandBox, a page anyone can edit to learn how to use the wiki."
+msgstr ""
+"Dette er [[SandKassen|SandBox]], en side som hvem som helst kan redigere for "
+"at lære hvordan en wiki bruges."
+
+#. type: Plain text
+msgid "Here's a paragraph."
+msgstr "Her er et afsnit."
+
+#. type: Plain text
+msgid "Here's another one with *emphasised* text."
+msgstr "her er et andet afsnit med *fremhævet* tekst."
+
+#. type: Title #
+#, no-wrap
+msgid "Header"
+msgstr "Overskrift"
+
+#. type: Title ##
+#, no-wrap
+msgid "Subheader"
+msgstr "Underoverskrift"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"> This is a blockquote.\n"
+">\n"
+"> This is the first level of quoting.\n"
+">\n"
+"> > This is nested blockquote.\n"
+">\n"
+"> Back to the first level.\n"
+msgstr ""
+"> Dette er et citat-område\n"
+">\n"
+"> Dette er første niveau citering.\n"
+">\n"
+"> > Dette er et indlejret citat-område.\n"
+">\n"
+"> Tilbage til det første niveau.\n"
+
+#. type: Plain text
+msgid "Numbered list"
+msgstr "Nummereret liste"
+
+#. type: Bullet: '1. '
+msgid "First item."
+msgstr "Første emne."
+
+#. type: Bullet: '1. '
+msgid "Another."
+msgstr "Et andet."
+
+#. type: Bullet: '1. '
+msgid "And another.."
+msgstr "Og et andet.."
+
+#. type: Plain text
+msgid "Bulleted list"
+msgstr "Unummereret liste"
+
+#. type: Bullet: '* '
+msgid "*item*"
+msgstr "*emne*"
+
+#. type: Bullet: '* '
+msgid "item"
+msgstr "emne"
+
+#. type: Plain text
+msgid "[[ikiwiki/WikiLink]]"
+msgstr "[[ikiwiki/WikiLink]]"
--- /dev/null
+# Danish translation of shortcuts page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!if test=\"enabled(shortcut)\"\n"
+" then=\"This wiki has shortcuts **enabled**.\"\n"
+" else=\"This wiki has shortcuts **disabled**.\"]]\n"
+msgstr ""
+"[[!if test=\"enabled(shortcut)\"\n"
+" then=\"Denne wiki har genveje **aktiveret**.\"\n"
+" else=\"Denne wiki har genveje **deaktiveret**.\"]]\n"
+
+#. type: Plain text
+msgid "Some examples of using shortcuts include:"
+msgstr "Nogle eksempler på brug af genveje:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!google foo]]\n"
+"\t\\[[!wikipedia War_of_1812]]\n"
+"\t\\[[!debbug 12345]]\n"
+"\tCheck the \\[[!cia ikiwiki desc=\"CIA page for %s\"]].\n"
+msgstr ""
+"\t\\[[!google foo]]\n"
+"\t\\[[!wikipedia War_of_1812]]\n"
+"\t\\[[!debbug 12345]]\n"
+
+#. type: Plain text
+msgid "This page controls what shortcut links the wiki supports."
+msgstr "Denne side styrer hvilke genveje wikien understøtter."
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=google url=\"http://www.google.com/search?q=%s\"]]"
+msgstr "[[!shortcut name=google url=\"http://www.google.com/search?q=%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=archive url=\"http://web.archive.org/*/%S\"]]"
+msgstr "[[!shortcut name=archive url=\"http://web.archive.org/*/%S\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=gmap url=\"http://maps.google.com/maps?q=%s\"]]"
+msgstr "[[!shortcut name=gmap url=\"http://maps.google.com/maps?q=%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=gmsg url=\"http://groups.google.com/groups?selm=%s\"]]"
+msgstr ""
+"[[!shortcut name=gmsg url=\"http://groups.google.com/groups?selm=%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=wikipedia url=\"http://en.wikipedia.org/wiki/%s\"]]"
+msgstr "[[!shortcut name=wikipedia url=\"http://en.wikipedia.org/wiki/%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=wikitravel url=\"http://wikitravel.org/en/%s\"]]"
+msgstr "[[!shortcut name=wikitravel url=\"http://wikitravel.org/en/%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=wiktionary url=\"http://en.wiktionary.org/wiki/%s\"]]"
+msgstr "[[!shortcut name=wiktionary url=\"http://en.wiktionary.org/wiki/%s\"]]"
+
+#. type: Bullet: '* '
+msgid ""
+"[[!shortcut name=debbug url=\"http://bugs.debian.org/%s\" desc=\"bug #%s\"]]"
+msgstr ""
+"[[!shortcut name=debbug url=\"http://bugs.debian.org/%s\" desc=\"bug #%s\"]]"
+
+#. type: Bullet: '* '
+msgid ""
+"[[!shortcut name=deblist url=\"http://lists.debian.org/debian-%s\" desc="
+"\"debian-%s@lists.debian.org\"]]"
+msgstr ""
+"[[!shortcut name=deblist url=\"http://lists.debian.org/debian-%s\" desc="
+"\"debian-%s@lists.debian.org\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=debpkg url=\"http://packages.debian.org/%s\"]]"
+msgstr "[[!shortcut name=debpkg url=\"http://packages.debian.org/%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=debpkgsid url=\"http://packages.debian.org/sid/%s\"]]"
+msgstr "[[!shortcut name=debpkgsid url=\"http://packages.debian.org/sid/%s\"]]"
+
+#. type: Bullet: '* '
+msgid "[[!shortcut name=debpts url=\"http://packages.qa.debian.org/%s\"]]"
+msgstr "[[!shortcut name=debpts url=\"http://packages.qa.debian.org/%s\"]]"
+
+#. type: Bullet: '* '
+msgid ""
+"[[!shortcut name=debmsg url=\"http://lists.debian.org/msgid-search/%s\"]]"
+msgstr ""
+"[[!shortcut name=debmsg url=\"http://lists.debian.org/msgid-search/%s\"]]"
+
+#. type: Bullet: '* '
+msgid ""
+"[[!shortcut name=debrt url=\"https://rt.debian.org/Ticket/Display.html?id=%s"
+"\"]]"
+msgstr ""
+"[[!shortcut name=debrt url=\"https://rt.debian.org/Ticket/Display.html?id=%s"
+"\"]]"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"* [[!shortcut name=debss url=\"http://snapshot.debian.net/package/%s\"]]\n"
+" * Usage: `\\[[!debss package]]`, `\\[[!debss package#version]]`, or `\\[[!debss package/version]]`. See http://snapshot.debian.net for details.\n"
+"* [[!shortcut name=debwiki url=\"http://wiki.debian.org/%s\"]]\n"
+"* [[!shortcut name=fdobug url=\"https://bugs.freedesktop.org/show_bug.cgi?id=%s\" desc=\"freedesktop.org bug #%s\"]]\n"
+"* [[!shortcut name=fdolist url=\"http://lists.freedesktop.org/mailman/listinfo/%s\" desc=\"%s@lists.freedesktop.org\"]]\n"
+"* [[!shortcut name=gnomebug url=\"http://bugzilla.gnome.org/show_bug.cgi?id=%s\" desc=\"GNOME bug #%s\"]]\n"
+"* [[!shortcut name=linuxbug url=\"http://bugzilla.kernel.org/show_bug.cgi?id=%s\" desc=\"Linux bug #%s\"]]\n"
+"* [[!shortcut name=mozbug url=\"https://bugzilla.mozilla.org/show_bug.cgi?id=%s\" desc=\"Mozilla bug #%s\"]]\n"
+"* [[!shortcut name=gnulist url=\"http://lists.gnu.org/mailman/listinfo/%s\" desc=\"%s@gnu.org\"]]\n"
+"* [[!shortcut name=marcmsg url=\"http://marc.info/?i=%s\"]]\n"
+"* [[!shortcut name=marclist url=\"http://marc.info/?l=%s\"]]\n"
+"* [[!shortcut name=gmane url=\"http://dir.gmane.org/gmane.%s\" desc=\"gmane.%s\"]]\n"
+"* [[!shortcut name=gmanemsg url=\"http://mid.gmane.org/%s\"]]\n"
+"* [[!shortcut name=cpan url=\"http://search.cpan.org/search?mode=dist&query=%s\"]]\n"
+"* [[!shortcut name=ctan url=\"http://tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=%s\"]]\n"
+"* [[!shortcut name=hoogle url=\"http://haskell.org/hoogle/?q=%s\"]]\n"
+"* [[!shortcut name=iki url=\"http://ikiwiki.info/%S/\"]]\n"
+"* [[!shortcut name=ljuser url=\"http://%s.livejournal.com/\"]]\n"
+"* [[!shortcut name=rfc url=\"http://www.ietf.org/rfc/rfc%s.txt\" desc=\"RFC %s\"]]\n"
+"* [[!shortcut name=c2 url=\"http://c2.com/cgi/wiki?%s\"]]\n"
+"* [[!shortcut name=meatballwiki url=\"http://www.usemod.com/cgi-bin/mb.pl?%s\"]]\n"
+"* [[!shortcut name=emacswiki url=\"http://www.emacswiki.org/cgi-bin/wiki/%s\"]]\n"
+"* [[!shortcut name=haskellwiki url=\"http://haskell.org/haskellwiki/%s\"]]\n"
+"* [[!shortcut name=dict url=\"http://www.dict.org/bin/Dict?Form=Dict1&Strategy=*&Database=*&Query=%s\"]]\n"
+"* [[!shortcut name=imdb url=\"http://imdb.com/find?q=%s\"]]\n"
+"* [[!shortcut name=gpg url=\"http://pgpkeys.mit.edu:11371/pks/lookup?op=vindex&exact=on&search=0x%s\"]]\n"
+"* [[!shortcut name=perldoc url=\"http://perldoc.perl.org/search.html?q=%s\"]]\n"
+"* [[!shortcut name=whois url=\"http://reports.internic.net/cgi/whois?whois_nic=%s&type=domain\"]]\n"
+"* [[!shortcut name=cve url=\"http://cve.mitre.org/cgi-bin/cvename.cgi?name=%s\"]]\n"
+"* [[!shortcut name=cia url=\"http://cia.vc/stats/project/%s\"]]\n"
+"* [[!shortcut name=ciauser url=\"http://cia.vc/stats/user/%s\"]]\n"
+"* [[!shortcut name=flickr url=\"http://www.flickr.com/photos/%s\"]]\n"
+"* [[!shortcut name=man url=\"http://linux.die.net/man/%s\"]]\n"
+"* [[!shortcut name=ohloh url=\"http://www.ohloh.net/projects/%s\"]]\n"
+msgstr ""
+"* [[!shortcut name=debss url=\"http://snapshot.debian.net/package/%s\"]]\n"
+" * Brug: `\\[[!debss package]]`, `\\[[!debss package#version]]`, eller `\\[[!debss package/version]]`. Se http://snapshot.debian.net for detaljer.\n"
+"* [[!shortcut name=debwiki url=\"http://wiki.debian.org/%s\"]]\n"
+"* [[!shortcut name=fdobug url=\"https://bugs.freedesktop.org/show_bug.cgi?id=%s\" desc=\"freedesktop.org bug #%s\"]]\n"
+"* [[!shortcut name=fdolist url=\"http://lists.freedesktop.org/mailman/listinfo/%s\" desc=\"%s@lists.freedesktop.org\"]]\n"
+"* [[!shortcut name=gnomebug url=\"http://bugzilla.gnome.org/show_bug.cgi?id=%s\" desc=\"GNOME bug #%s\"]]\n"
+"* [[!shortcut name=linuxbug url=\"http://bugzilla.kernel.org/show_bug.cgi?id=%s\" desc=\"Linux bug #%s\"]]\n"
+"* [[!shortcut name=mozbug url=\"https://bugzilla.mozilla.org/show_bug.cgi?id=%s\" desc=\"Mozilla bug #%s\"]]\n"
+"* [[!shortcut name=gnulist url=\"http://lists.gnu.org/mailman/listinfo/%s\" desc=\"%s@gnu.org\"]]\n"
+"* [[!shortcut name=marcmsg url=\"http://marc.info/?i=%s\"]]\n"
+"* [[!shortcut name=marclist url=\"http://marc.info/?l=%s\"]]\n"
+"* [[!shortcut name=gmane url=\"http://dir.gmane.org/gmane.%s\" desc=\"gmane.%s\"]]\n"
+"* [[!shortcut name=gmanemsg url=\"http://mid.gmane.org/%s\"]]\n"
+"* [[!shortcut name=cpan url=\"http://search.cpan.org/search?mode=dist&query=%s\"]]\n"
+"* [[!shortcut name=ctan url=\"http://tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=%s\"]]\n"
+"* [[!shortcut name=hoogle url=\"http://haskell.org/hoogle/?q=%s\"]]\n"
+"* [[!shortcut name=iki url=\"http://ikiwiki.info/%S/\"]]\n"
+"* [[!shortcut name=ljuser url=\"http://%s.livejournal.com/\"]]\n"
+"* [[!shortcut name=rfc url=\"http://www.ietf.org/rfc/rfc%s.txt\" desc=\"RFC %s\"]]\n"
+"* [[!shortcut name=c2 url=\"http://c2.com/cgi/wiki?%s\"]]\n"
+"* [[!shortcut name=meatballwiki url=\"http://www.usemod.com/cgi-bin/mb.pl?%s\"]]\n"
+"* [[!shortcut name=emacswiki url=\"http://www.emacswiki.org/cgi-bin/wiki/%s\"]]\n"
+"* [[!shortcut name=haskellwiki url=\"http://haskell.org/haskellwiki/%s\"]]\n"
+"* [[!shortcut name=dict url=\"http://www.dict.org/bin/Dict?Form=Dict1&Strategy=*&Database=*&Query=%s\"]]\n"
+"* [[!shortcut name=imdb url=\"http://imdb.com/find?q=%s\"]]\n"
+"* [[!shortcut name=gpg url=\"http://pgpkeys.mit.edu:11371/pks/lookup?op=vindex&exact=on&search=0x%s\"]]\n"
+"* [[!shortcut name=perldoc url=\"http://perldoc.perl.org/search.html?q=%s\"]]\n"
+"* [[!shortcut name=whois url=\"http://reports.internic.net/cgi/whois?whois_nic=%s&type=domain\"]]\n"
+"* [[!shortcut name=cve url=\"http://cve.mitre.org/cgi-bin/cvename.cgi?name=%s\"]]\n"
+"* [[!shortcut name=cia url=\"http://cia.vc/stats/project/%s\"]]\n"
+"* [[!shortcut name=ciauser url=\"http://cia.vc/stats/user/%s\"]]\n"
+"* [[!shortcut name=flickr url=\"http://www.flickr.com/photos/%s\"]]\n"
+"* [[!shortcut name=man url=\"http://linux.die.net/man/%s\"]]\n"
+"* [[!shortcut name=ohloh url=\"http://www.ohloh.net/projects/%s\"]]\n"
+
+#. type: Plain text
+msgid ""
+"To add a new shortcut, use the `shortcut` [[ikiwiki/directive]]. In the url, "
+"\"%s\" is replaced with the text passed to the named shortcut, after url-"
+"encoding it, and '%S' is replaced with the raw, non-encoded text. The "
+"optional `desc` parameter controls the description of the link."
+msgstr ""
+"Tilføj en ny genvej med [[direktivet|ikiwiki/directive]] `shortcut`. I URLen "
+"erstattes \"%s\" med teksten overdraget til den navngivne genvej, efter URL-"
+"omkodning af den, og '%S' erstattes med den rå, ukodede tekst. Den valgfri "
+"`desc`-parameter styrer beskrivelsen af henvisningen."
+
+#. type: Plain text
+msgid ""
+"Remember that the `name` you give the shortcut will become a new [[ikiwiki/"
+"directive]]. Avoid using a `name` that conflicts with an existing "
+"directive. These directives also accept a `desc` parameter that will "
+"override the one provided at definition time."
+msgstr ""
+"Husk at `name`-parameteren som du tildeler genvejen bliver et nyt [[direktiv|"
+"ikiwiki/directive]]. Undgå et navn som er i strid med et eksisterende "
+"direktiv. Disse direktiver accepterer også en `desc`-parameter som vil "
+"overskygge den der blev angivet ved definitionen."
+
+#. type: Plain text
+msgid ""
+"If you come up with a shortcut that you think others might find useful, "
+"consider contributing it to the [shortcuts page on the ikiwiki ikiwiki]"
+"(http://ikiwiki.info/shortcuts/), so that future versions of ikiwiki will "
+"include your shortcut in the standard underlay."
+msgstr ""
+"Hvis du finder på en genvej som du mener andre kunne få glæde af også, kan "
+"du overveje at bidrage med den til [shortcuts-siden på ikiwiki ikiwikien]"
+"(http://ikiwiki.info/shortcuts/), så fremtidige versioner af ikiwiki "
+"inkluderer din genvej i standardunderlaget."
--- /dev/null
+# Danish translation of templates page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!if test=\"enabled(template)\"\n"
+"then=\"This wiki has templates **enabled**.\"\n"
+"else=\"This wiki has templates **disabled**.\"\n"
+"]]\n"
+msgstr ""
+"[[!if test=\"enabled(template)\"\n"
+"then=\"Denne wiki har skabeloner **aktiveret**.\"\n"
+"else=\"Denne wiki har skabeloner **deaktiveret**.\" ]]\n"
+
+#. type: Plain text
+msgid ""
+"Templates are files that can be filled out and inserted into pages in the "
+"wiki."
+msgstr "Skabeloner er filer som kan blive udfyldt og indsat på sider i wikien."
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!if test=\"enabled(template) and enabled(inline)\" then=\"\"\"\n"
+msgstr "[[!if test=\"enabled(template) and enabled(inline)\" then=\"\"\"\n"
+
+#. type: Plain text
+msgid ""
+"These templates are available for inclusion onto other pages in this wiki:"
+msgstr ""
+"Disse skabeloner er tilgængelige til indsættelse på andre sider i denne wiki:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"[[!inline pages=\"templates/* and !*/discussion\" feeds=no archive=yes\n"
+"sort=title template=titlepage]]\n"
+msgstr ""
+"[[!inline pages=\"templates/* and !*/discussion\" feeds=no archive=yes\n"
+"sort=title template=titlepage]]\n"
+
+#. type: Title ##
+#, no-wrap
+msgid "Using a template"
+msgstr "Brug af skabelon"
+
+#. type: Plain text
+msgid "Using a template works like this:"
+msgstr "En skabelon bruges som her:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!template id=note text=\"\"\"Here is the text to insert into my note.\"\"\"]]\n"
+msgstr "\t\\[[!template id=note text=\"\"\"Her er teksten til at sætte ind i min note.\"\"\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This fills out the [[note]] template, filling in the `text` field with the "
+"specified value, and inserts the result into the page."
+msgstr ""
+"Dette udfylder [[note]]-skabelonen, ved at erstatte `text`-feltet med den "
+"angivne værdi og indsætte resultatet på siden."
+
+#. type: Plain text
+msgid ""
+"Generally, a value can include any markup that would be allowed in the wiki "
+"page outside the template. Triple-quoting the value even allows quotes to be "
+"included in it. Combined with multi-line quoted values, this allows for "
+"large chunks of marked up text to be embedded into a template:"
+msgstr ""
+"Generelt kan en værdi indeholde enhver opmærkning som ville være tilladt på "
+"wikisiden udenfor skabelonen. Trippel-citering af værdien tillader endda at "
+"bruge citering som del af værdien. Kombineret med flerlinje-citerede værdier "
+"tillader dette indlejring af store klumper af opmærket tekst i skabelonen:"
+
+#. type: Plain text
+#, no-wrap
+msgid " \\[[!template id=foo name=\"Sally\" color=\"green\" age=8 notes=\"\"\"\n"
+msgstr " \\[[!template id=foo name=\"Sally\" color=\"grøn\" age=8 notes=\"\"\"\n"
+
+#. type: Bullet: ' * '
+msgid "\\[[Charley]]'s sister."
+msgstr "\\[[Charley]]'s søster."
+
+#. type: Bullet: ' * '
+msgid "\"I want to be an astronaut when I grow up.\""
+msgstr "\"Jeg vil være en astronaut når jeg bliver stor.\""
+
+#. type: Bullet: ' * '
+msgid "Really 8 and a half."
+msgstr "Egentligt 8 og et halvt."
+
+#. type: Title ##
+#, no-wrap
+msgid "Creating a template"
+msgstr "Oprettelse af skabelon"
+
+#. type: Plain text
+msgid ""
+"To create a template, simply add a template directive to a page, and the "
+"page will provide a link that can be used to create the template. The "
+"template is a regular wiki page, located in the `templates/` subdirectory "
+"inside the source directory of the wiki."
+msgstr ""
+"Opret en skabelon ved simpelthen at tilføje skabelon-direktivet til en side, "
+"så vil siden vise en henvisning som kan bruges til at oprette skabelonen. "
+"Skabelonen er en normal wikiside, placeret i `templates/` undermappen indeni "
+"wikiens kildemappe."
+
+#. type: Plain text
+msgid ""
+"The template uses the syntax used by the [[!cpan HTML::Template]] perl "
+"module, which allows for some fairly complex things to be done. Consult its "
+"documentation for the full syntax, but all you really need to know are a few "
+"things:"
+msgstr ""
+"Skabelonen bruger samme syntax som perl-modulet [[!cpan HTML::Template]] som "
+"giver mulighed for at lave ret komplekse ting. Læs dokumentationen for den "
+"fulde syntaks, men alt hvad du reelt behøver at vide er nogle få ting:"
+
+#. type: Bullet: '* '
+msgid ""
+"Each parameter you pass to the template directive will generate a template "
+"variable. There are also some pre-defined variables like PAGE and BASENAME."
+msgstr ""
+"Ethvert parameter du angiver til skabelondirektivet vil danne en "
+"skabelonvariabel. Der er også nogle foruddefinerede variable som PAGE og "
+"BASENAME."
+
+#. type: Bullet: '* '
+msgid ""
+"To insert the value of a variable, use `<TMPL_VAR variable>`. Wiki markup in "
+"the value will first be converted to html."
+msgstr ""
+"Brug `<TMPL_VAR variabel>` til at indsætte værdien af en variabel. Wiki-"
+"opmærkning i værdien bliver først konverteret til html."
+
+#. type: Bullet: '* '
+msgid ""
+"To insert the raw value of a variable, with wiki markup not yet converted to "
+"html, use `<TMPL_VAR raw_variable>`."
+msgstr ""
+"Brug `<TMPL_VAR raw_variabel>` til at indsætte den rå værdi af en variabel, "
+"med wiki-opmærkning endnu ikke konverteret til html."
+
+#. type: Bullet: '* '
+msgid ""
+"To make a block of text conditional on a variable being set use `<TMPL_IF "
+"NAME=\"variable\">text</TMPL_IF>`."
+msgstr ""
+"Gør en tekstblok betinget af at en variabel er i brug med `<TMPL_IF NAME="
+"\"variabel\">tekst</TMPL_IF>`."
+
+#. type: Bullet: '* '
+msgid ""
+"To use one block of text if a variable is set and a second if it's not, use "
+"`<TMPL_IF NAME=\"variable\">text<TMPL_ELSE>other text</TMPL_IF>`"
+msgstr ""
+"Brug een tekstblok hvis en variabel er i brug, og en anden hvis ikke, med "
+"`<TMPL_IF NAME=\"variabel\">tekst<TMPL_ELSE>anden tekst</TMPL_IF>`"
+
+#. type: Plain text
+msgid "Here's a sample template:"
+msgstr ""
+"Her er et eksempel på en skabelon (det anbefales at bruge engelske "
+"variabelnavne for at undgå problemer med æøå og andre specialtegn):"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" <span class=\"infobox\">\n"
+" Name: \\[[<TMPL_VAR raw_name>]]<br />\n"
+" Age: <TMPL_VAR age><br />\n"
+" <TMPL_IF NAME=\"color\">\n"
+" Favorite color: <TMPL_VAR color><br />\n"
+" <TMPL_ELSE>\n"
+" No favorite color.<br />\n"
+" </TMPL_IF>\n"
+" <TMPL_IF NAME=\"notes\">\n"
+" <hr />\n"
+" <TMPL_VAR notes>\n"
+" </TMPL_IF>\n"
+" </span>\n"
+msgstr ""
+" <span class=\"infobox\">\n"
+" Navn: \\[[<TMPL_VAR raw_name>]]<br />\n"
+" Alder: <TMPL_VAR age><br />\n"
+" <TMPL_IF NAME=\"color\">\n"
+" Favoritfarve: <TMPL_VAR color><br />\n"
+" <TMPL_ELSE>\n"
+" Ingen favoritfarve.<br />\n"
+" </TMPL_IF>\n"
+" <TMPL_IF NAME=\"notes\">\n"
+" <hr />\n"
+" <TMPL_VAR notes>\n"
+" </TMPL_IF>\n"
+" </span>\n"
+
+#. type: Plain text
+msgid ""
+"The filled out template will be formatted the same as the rest of the page "
+"that contains it, so you can include WikiLinks and all other forms of wiki "
+"markup in the template. Note though that such WikiLinks will not show up as "
+"backlinks to the page that uses the template."
+msgstr ""
+"Den udfyldte skabelon vil blive formateret som resten af siden den er "
+"inkluderet i, så du kan medtage WikiLinks og alle andre former for wiki- "
+"opmærkning i skabelonen. Bemærk dog at sådanne WikiLinks ikke vil dukke op "
+"som krydshenvisninger (backlinks) til den side som anvender skabelonen."
+
+#. type: Plain text
+msgid ""
+"Note the use of \"raw_name\" inside the [[ikiwiki/WikiLink]] generator. This "
+"ensures that if the name contains something that might be mistaken for wiki "
+"markup, it's not converted to html before being processed as a [[ikiwiki/"
+"WikiLink]]."
+msgstr ""
+"Bemærk brugen af \"raw_name\" indeni [[ikiwiki/WikiLink]]-generatoren. Dette "
+"sikrer at hvor navnet indeholder noget som måske kan fejltolkes som wiki-"
+"opmærkning, bliver det ikke konverteret til html før det er blevet behandlet "
+"som en [[ikiwiki/WikiLink]]."
--- /dev/null
+# Danish translation of basewiki/templates/note page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"<div class=\"notebox\">\n"
+"<TMPL_VAR text>\n"
+"</div>\n"
+"<TMPL_UNLESS NAME=\"text\">\n"
+"Use this template to insert a note into a page. The note will be styled to\n"
+"float to the right of other text on the page. This template has one\n"
+"parameter:\n"
+"<ul>\n"
+"<li>`text` - the text to display in the note\n"
+"</ul>\n"
+"</TMPL_UNLESS>\n"
+msgstr ""
+"<div class=\"notebox\">\n"
+"<TMPL_VAR text>\n"
+"</div>\n"
+"<TMPL_UNLESS NAME=\"text\">\n"
+"Brug denne skabelon til at indsætte en note på en side. Noten vil blive\n"
+"udsmykket til at flyde til højre for den øvrige tekst på siden. Denne\n"
+"skabelon har et parameter:\n"
+"<ul>\n"
+"<li>`text` - teksten som vises i noten\n"
+"</ul>\n"
+"</TMPL_UNLESS>\n"
--- /dev/null
+# Danish translation of basewiki/templates/popup page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"<TMPL_UNLESS NAME=\"mouseover\">\n"
+"Use this template to create a popup window that is displayed when the mouse\n"
+"is over part of the page. This template has two parameters:\n"
+"<ul>\n"
+"<li>`mouseover` - This is the text or other content that triggers the\n"
+"popup.\n"
+"<li>`popup` - This should be the content of the popup window. It can be\n"
+"anything, even images or a whole little wiki page, but should not be too\n"
+"large for good usability.\n"
+"</ul>\n"
+"Note that browsers that do not support the CSS will display the popup\n"
+"inline in the page, inside square brackets.\n"
+"</TMPL_UNLESS>\n"
+"<span class=\"popup\"><TMPL_VAR mouseover>\n"
+"<span class=\"paren\">[</span><span class=\"balloon\"><TMPL_VAR popup></span><span class=\"paren\">]</span>\n"
+"</span>\n"
+msgstr ""
+"<TMPL_UNLESS NAME=\"mouseover\">\n"
+"Brug denne skabelon til at lave et popup-vindue som vises når musemarkøren er\n"
+"henover en del af siden. Denne skabelon har to parametre:\n"
+"<ul>\n"
+"<li>`mouseover` - Dette er teksten eller andet indhold som udløser popup'en.\n"
+"<li>`popup` - Her angives indeholdet af popup-vinduet. Det kan være hvad som\n"
+"helst, endda billeder eller hele små wikisider, men bør ikke være for stort af\n"
+"hensyn til brugervenligheden.\n"
+"</ul>\n"
+"Bemærk at browsere som ikke understøtter CSS-koden vil vise popup'en indlejret\n"
+"på siden, indenfor lodrette klammer.\n"
+"</TMPL_UNLESS>\n"
+"<span class=\"popup\"><TMPL_VAR mouseover>\n"
+"<span class=\"paren\">[</span><span class=\"balloon\"><TMPL_VAR popup></span><span class=\"paren\">]</span>\n"
+"</span>\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/aggregrate page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `aggregate` directive is supplied by the [[!iki plugins/aggregate "
+"desc=aggregate]] plugin. This plugin requires extra setup, specifically, a "
+"cron job. See the plugin's documentation for details."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows content from other feeds to be aggregated into the "
+"wiki. Aggregate a feed as follows:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!aggregate name=\"example blog\" dir=\"example\"\n"
+"\tfeedurl=\"http://example.com/index.rss\"\n"
+"\turl=\"http://example.com/\" updateinterval=\"15\"]]\n"
+msgstr ""
+"\t\\[[!aggregate name=\"eksempel blog\" dir=\"eksempel\"\n"
+"\tfeedurl=\"http://eksempel.dk/index.rss\"\n"
+"\turl=\"http://eksempel.dk/\" updateinterval=\"15\"]]\n"
+
+#. type: Plain text
+msgid ""
+"That example aggregates posts from the specified RSS feed, updating no more "
+"frequently than once every 15 minutes (though possibly less frequently, if "
+"the cron job runs less frequently than that), and puts a page per post under "
+"the example/ directory in the wiki."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"You can then use ikiwiki's [[inline]] directive to create a blog of one or "
+"more aggregated feeds. For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"internal(example/*)\"]]\n"
+msgstr "\t\\[[!inline pages=\"internal(eksempel/*)\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Note the use of `internal()` in the [[ikiwiki/PageSpec]] to match aggregated "
+"pages. By default, aggregated pages are internal pages, which prevents them "
+"from showing up directly in the wiki, and so this special [[PageSpec]] is "
+"needed to match them."
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Plain text
+msgid ""
+"Here are descriptions of all the supported parameters to the `aggregate` "
+"directive:"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`name` - A name for the feed. Each feed must have a unique name. Required."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`url` - The url to the web page for the feed that's being aggregated. "
+"Required."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`dir` - The directory in the wiki where pages should be saved. Optional, if "
+"not specified, the directory is based on the name of the feed."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`feedurl` - The url to the feed. Optional, if it's not specified ikiwiki "
+"will look for feeds on the `url`. RSS and atom feeds are supported."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`updateinterval` - How often to check for new posts, in minutes. Default is "
+"15 minutes."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`expireage` - Expire old items from this feed if they are older than a "
+"specified number of days. Default is to never expire on age."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`expirecount` - Expire old items from this feed if there are more than the "
+"specified number total. Oldest items will be expired first. Default is to "
+"never expire on count."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`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."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`template` - Template to use for creating the aggregated pages. Defaults to "
+"aggregatepost."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Note that even if you are using subversion or another revision control "
+"system, pages created by aggregation will *not* be checked into revision "
+"control."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/brokenlinks page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `brokenlinks` directive is supplied by the [[!iki plugins/brokenlinks "
+"desc=brokenlinks]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive generates a list of broken links on pages in the wiki. This "
+"is a useful way to find pages that still need to be written, or links that "
+"are written wrong."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The optional parameter \"pages\" can be a [[ikiwiki/PageSpec]] specifying "
+"the pages to search for broken links, default is search them all."
+msgstr ""
+
+#. type: Plain text
+msgid "Example:"
+msgstr "Eksempel:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!brokenlinks pages=\"* and !recentchanges\"]]\n"
+msgstr "\t\\[[!brokenlinks pages=\"* and !recentchanges\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/calendar page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `calendar` directive is supplied by the [[!iki plugins/calendar "
+"desc=calendar]] plugin. This plugin requires extra setup. See the plugin "
+"documentation for details."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive displays a calendar, similar to the typical calendars shown "
+"on some blogs."
+msgstr ""
+
+#. type: Title #
+#, no-wrap
+msgid "examples"
+msgstr "exempler"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!calendar ]]\n"
+msgstr "\t\\[[!calendar ]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!calendar type=\"month\" pages=\"blog/* and !*/Discussion\"]]\n"
+msgstr "\t\\[[!calendar type=\"month\" pages=\"blog/* and !*/Discussion\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!calendar type=\"year\" year=\"2005\" pages=\"blog/* and !*/Discussion\"]]\n"
+msgstr "\t\\[[!calendar type=\"year\" year=\"2005\" pages=\"blog/* and !*/Discussion\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The calendar is essentially a fancy front end to archives of previous pages, "
+"usually used for blogs. It can produce a calendar for a given month, or a "
+"list of months for a given year."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The month format calendar simply links to any page posted on each day of the "
+"month. The year format calendar links to archive pages, with names like "
+"`archives/2007` (for all of 2007) and `archives/2007/01` (for January, "
+"2007). For this to work, you'll need to create these archive pages. They "
+"typically use [[inline]] to display or list pages created in the given time "
+"frame."
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Bullet: '* '
+msgid ""
+"`type` - Used to specify the type of calendar wanted. Can be one of \"month"
+"\" or \"year\". The default is a month view calendar."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`pages` - Specifies the [[ikiwiki/PageSpec]] of pages to link to from the "
+"month calendar. Defaults to \"*\"."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`archivebase` - Configures the base of the archives hierarchy. The default "
+"is \"archives\". Note that this default can also be overridden for the whole "
+"wiki by setting `archivebase` in ikiwiki's setup file."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`year` - The year for which the calendar is requested. Defaults to the "
+"current year."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`month` - The numeric month for which the calendar is requested, in the "
+"range 1..12. Used only for the month view calendar, and defaults to the "
+"current month."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`week_start_day` - A number, in the range 0..6, which represents the day of "
+"the week that the month calendar starts with. 0 is Sunday, 1 is Monday, and "
+"so on. Defaults to 0, which is Sunday."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`months_per_row` - In the annual calendar, number of months to place in each "
+"row. Defaults to 3."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/color page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `color` directive is supplied by the [[!iki plugins/color desc=color]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive can be used to color a piece of text on a page. It can be "
+"used to set the foreground and/or background color of the text."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"You can use a color name (e.g. `white`) or HTML code (e.g. `#ffffff`) to "
+"define colors."
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "examples"
+msgstr "eksempler"
+
+#. type: Plain text
+msgid ""
+"Here the foreground color is defined as a word, while the background color "
+"is defined as a HTML color code:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!color foreground=white background=#ff0000 text=\"White text on red background\"]]\n"
+msgstr "\t\\[[!color foreground=white background=#ff0000 text=\"Hvid tekst på rød baggrund\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The background color is missing, so the text is displayed on default "
+"background:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!color foreground=white text=\"White text on default color background\"]]\n"
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The foreground is missing, so the text has the default foreground color:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!color background=#ff0000 text=\"Default color text on red background\"]]\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/comment page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `comment` directive is supplied by the [[!iki plugins/comments "
+"desc=comments]] plugin, and is used to add a comment to a page. Typically, "
+"the directive is the only thing on a comment page, and is filled out by the "
+"comment plugin when a user posts a comment."
+msgstr ""
+
+#. type: Plain text
+msgid "Example:"
+msgstr "Eksempel:"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!comment format=mdwn\n"
+"\tusername=\"foo\"\n"
+"\tsubject=\"Bar\"\n"
+"\tdate=\"2009-06-02T19:05:01Z\"\n"
+"\tcontent=\"\"\"\n"
+msgstr ""
+"\t\\[[!comment format=mdwn\n"
+"\tusername=\"foo\"\n"
+"\tsubject=\"Bar\"\n"
+"\tdate=\"2009-06-02T19:05:01Z\"\n"
+"\tcontent=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tBlah blah.\n"
+"\t\"\"\"\n"
+msgstr ""
+"\tBlah blah.\n"
+"\t\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t]]\n"
+msgstr "\t]]\n"
+
+#. type: Title ##
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Plain text
+msgid ""
+"The only required parameter is `content`, the others just add or override "
+"metadata of the comment."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`content` - Text to display for the comment. Note that [[directives|ikiwiki/"
+"directive]] may not be allowed, depending on the configuration of the "
+"comment plugin."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`format` - Specifies the markup used for the content."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`subject` - Subject for the comment."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`date` - Date the comment was posted. Can be entered in nearly any format, "
+"since it's parsed by [[!cpan TimeDate]]"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`username` - Used to record the username (or OpenID) of a logged in "
+"commenter."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`ip` - Can be used to record the IP address of a commenter, if they posted "
+"anonymously."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`claimedauthor` - Records the name that the user entered, if anonmous "
+"commenters are allowed to enter their (unverified) name."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/copy page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta redir=/ikiwiki/directive/cutpaste]]\n"
+msgstr "[[!meta redir=/ikiwiki/directive/cutpaste]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/cut page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta redir=/ikiwiki/directive/cutpaste]]\n"
+msgstr "[[!meta redir=/ikiwiki/directive/cutpaste]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/cutpaste page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `copy`, `cut` and `paste` directives are supplied by the [[!iki plugins/"
+"cutpaste desc=cutpaste]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"With these directives you can store and recall pieces of text in a page:"
+msgstr ""
+
+#. type: Bullet: ' * '
+msgid ""
+"`\\[[!cut id=name text=\"text\"]]` memorizes the text allowing to recall it "
+"using the given ID. The text being cut is not included in the output."
+msgstr ""
+
+#. type: Bullet: ' * '
+msgid ""
+"`\\[[!copy id=name text=\"text\"]]` memorizes the text allowing to recall it "
+"using the given ID. The text being cut *is* included in the output."
+msgstr ""
+
+#. type: Bullet: ' * '
+msgid "`\\[[!paste id=name]]` is replaced by the previously memorized text."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The text being cut, copied and pasted can freely include wiki markup, "
+"including more calls to cut, copy and paste."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"You do not need to memorize the text before using it: a cut directive can "
+"follow the paste directive that uses its text. In fact, this is quite "
+"useful to postpone big blocks of text like long annotations and have a more "
+"natural flow. For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!toggleable id=\"cut\" text=\"[[!paste id=cutlongdesc]]\"]]\n"
+"\t\\[[!toggleable id=\"copy\" text=\"[[!paste id=copylongdesc]]\"]]\n"
+"\t\\[[!toggleable id=\"paste\" text=\"[[!paste id=pastelongdesc]]\"]]\n"
+msgstr ""
+"\t\\[[!toggleable id=\"cut\" text=\"[[!paste id=cutlongdesc]]\"]]\n"
+"\t\\[[!toggleable id=\"copy\" text=\"[[!paste id=copylongdesc]]\"]]\n"
+"\t\\[[!toggleable id=\"paste\" text=\"[[!paste id=pastelongdesc]]\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t[...some time later...]\n"
+msgstr "\t[...noget tid senere...]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!cut id=cutlongdesc text=\"\"\"\n"
+msgstr "\t\\[[!cut id=cutlongdesc text=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t blah blah blah\n"
+msgstr "\t blah blah blah\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!cut id=copylongdesc text=\"\"\"\n"
+msgstr "\t\\[[!cut id=copylongdesc text=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!cut id=pastelongdesc text=\"\"\"\n"
+msgstr "\t\\[[!cut id=pastelongdesc text=\"\"\"\n"
+
+#. type: Plain text
+msgid ""
+"This can potentially be used to create loops, but ikiwiki is clever and "
+"breaks them."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Since you can paste without using double quotes, copy and paste can be used "
+"to nest directives that require multiline parameters inside each other:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!toggleable id=foo text=\"\"\"\n"
+msgstr "\t\\[[!toggleable id=foo text=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t [[!toggleable id=bar text=\"[[!paste id=baz]]\"]]\n"
+msgstr "\t [[!toggleable id=bar text=\"[[!paste id=baz]]\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!cut id=baz text=\"\"\"\n"
+msgstr "\t\\[[!cut id=baz text=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\tmultiline parameter!\n"
+msgstr "\tflere linjer lang parameter!\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/edittemplate page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `edittemplate` directive is supplied by the [[!iki plugins/edittemplate "
+"desc=edittemplate]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows registering template pages, that provide default "
+"content for new pages created using the web frontend. To register a "
+"template, insert a [[ikiwiki/directive/template]] directive on some other "
+"page."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!edittemplate template=\"bugtemplate\" match=\"bugs/*\"]]\n"
+msgstr "\t\\[[!edittemplate template=\"bugtemplate\" match=\"bugs/*\"]]\n"
+
+#. type: Plain text
+msgid ""
+"In the above example, the page named \"bugtemplate\" is registered as a "
+"template to be used when any page named \"bugs/*\" is created. To avoid the "
+"directive displaying a note about the template being registered, add "
+"\"silent=yes\"."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Often the template page contains a simple skeleton for a particular type of "
+"page. For the bug report pages in the above example, it might look something "
+"like:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tPackage: \n"
+"\tVersion: \n"
+"\tReproducible: y/n\n"
+"\tDetails:\n"
+msgstr ""
+"\tPackage: \n"
+"\tVersion: \n"
+"\tReproducible: y/n\n"
+"\tDetails:\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"The template page can also contain [[!cpan HTML::Template]] directives,\n"
+"similar to other ikiwiki [[templates]]. Currently only one variable is\n"
+"set: `<TMPL_VAR name>` is replaced with the name of the page being\n"
+"created.\n"
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"It's generally not a good idea to put the `edittemplate` directive in the "
+"template page itself, since the directive would then be included as part of "
+"the template on new pages, which would then in turn be registered as "
+"templates. If multiple pages are registered as templates for a new page, an "
+"arbitrary one is chosen, so that could get confusing."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/format page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `format` directive is supplied by the [[!iki plugins/format "
+"desc=format]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The directive allows formatting a chunk of text using any available page "
+"format. It takes two parameters. First is the type of format to use, ie the "
+"extension that would be used for a standalone file of this type. Second is "
+"the text to format."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"For example, this will embed an otl outline inside a page using mdwn or some "
+"other format:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!format otl \"\"\"\n"
+msgstr "\t\\[[!format otl \"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tfoo\n"
+"\t\t1\n"
+"\t\t2\n"
+"\tbar\n"
+"\t\t3\n"
+"\t\t4\n"
+msgstr ""
+"\tfoo\n"
+"\t\t1\n"
+"\t\t2\n"
+"\tbar\n"
+"\t\t3\n"
+"\t\t4\n"
+
+#. type: Plain text
+msgid ""
+"Note that if the highlight plugin is enabled, this directive can also be "
+"used to display syntax highlighted code. Many languages and formats are "
+"supported. For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[format perl \"\"\"\n"
+msgstr "\t\\[[format perl \"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\tprint \"hello, world\\n\";\n"
+msgstr "\tprint \"hej, verden\\n\";\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/fortune page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `fortune` directive is supplied by the [[!iki plugins/fortune "
+"desc=fortune]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This just uses the `fortune` program to insert a fortune cookie into the "
+"page. Usage:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!fortune ]]\n"
+msgstr "\t\\[[!fortune ]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/graph page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `graph` directive is supplied by the [[!iki plugins/graphviz "
+"desc=graphviz]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows embedding [graphviz](http://www.graphviz.org/) graphs "
+"in a page. Example usage:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!graph src=\"a -> b -> c; a -> c;\"]]\n"
+msgstr "\t\\[[!graph src=\"a -> b -> c; a -> c;\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Note that graphs will only show up in previews if your browser has [[!"
+"wikipedia data: URI]] support, or if the same graph already exists on that "
+"page."
+msgstr ""
+
+#. type: Plain text
+msgid "The `graph` directive supports the following parameters:"
+msgstr ""
+
+#. type: Bullet: '- '
+msgid "`src` - The graphviz source to render."
+msgstr ""
+
+#. type: Bullet: '- '
+msgid ""
+"`type` - The type of graph to render: `graph` or `digraph`. Defaults to "
+"`digraph`."
+msgstr ""
+
+#. type: Bullet: '- '
+msgid ""
+"`prog` - The graphviz program to render with: `dot`, `neato`, `fdp`, "
+"`twopi`, or `circo`. Defaults to `dot`."
+msgstr ""
+
+#. type: Bullet: '- '
+msgid ""
+"`height`, `width` - Limit the size of the graph to a given height and width, "
+"in inches. You must specify both to limit the size; otherwise, graphviz will "
+"choose a size, without any limit."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/haiku page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `haiku` directive is supplied by the [[!iki plugins/haiku desc=haiku]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows inserting a randomly generated haiku into a wiki "
+"page. Just type:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!haiku hint=\"argument\"]]\n"
+msgstr "\t\\[[!haiku hint=\"argument\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!haiku hint=\"argument test\"]]\n"
+msgstr "[[!haiku hint=\"argument test\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The hint parameter can be omitted, it only provides the generator a hint of "
+"what to write the haiku about. If no hint is given, it might base it on the "
+"page name. Since the vocabulary it knows is very small, many hints won't "
+"affect the result at all."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of if page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `if` directive is supplied by the [[!iki plugins/conditional "
+"desc=conditional]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"With this directive, you can make text be conditionally displayed on a "
+"page. For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!if test=\"enabled(smiley)\"\n"
+"\t then=\"The smiley plugin is enabled :-)\"\n"
+"\t else=\"No smiley plugin here..\"]]\n"
+msgstr ""
+"[[!if test=\"enabled(smiley)\"\n"
+" then=\"Smiley-udvidelsen er aktiveret :-)\"\n"
+" else=\"Ingen smiley-udvidelse her...\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If the specified `test` succeeds, the `then` text will be displayed, "
+"otherwise the `else` text will be displayed. The `else` part is optional."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The `then` and `else` values can include any markup that would be allowed in "
+"the wiki page outside the template. Triple-quoting the values even allows "
+"quotes to be included."
+msgstr ""
+"Værdierne `then` og `else` kan indeholde enhver opmærkning som ville være "
+"tilladt på wikisiden udenfor skabelonen. Trippel-citering af værdien "
+"tillader endda at bruge citering som del af værdien."
+
+#. type: Plain text
+msgid ""
+"The `test` is a [[ikiwiki/PageSpec]]; if it matches any page in the wiki "
+"then it succeeds. So you can do things like testing for the existence of a "
+"page or pages, testing to see if any pages were created in a given month, "
+"and so on."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"If you want the [[ikiwiki/PageSpec]] to only match against the page that "
+"contains the conditional, rather than matching against all pages in the "
+"wiki, set the \"all\" parameter to \"no\"."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"In an `if` directive, the regular [[ikiwiki/PageSpec]] syntax is expanded "
+"with the following additional tests:"
+msgstr ""
+"I et `if`-direktiv udvides den normale [[ikiwiki/PageSpec]]-syntaks med "
+"følgende yderligere tests:"
+
+#. type: Bullet: '* '
+msgid "enabled(plugin)"
+msgstr "enabled(udvielse)"
+
+#. type: Plain text
+#, no-wrap
+msgid " Tests whether the specified plugin is enabled.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "sourcepage(glob)"
+msgstr "sourcepage(glob)"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Tests whether the glob matches the name of the page that contains the\n"
+" conditional.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "destpage(glob)"
+msgstr "destpage(glob)"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Tests whether the glob matches the name of the page that is being built.\n"
+" That might be different than the name of the page that contains the\n"
+" conditional, if it's being inlined into another page.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "included()"
+msgstr "included()"
+
+#. type: Plain text
+#, no-wrap
+msgid " Tests whether the page is being included onto another page.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/img page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `img` directive is supplied by the [[!iki plugins/img desc=img]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This is an image handling directive. While ikiwiki supports inlining full-"
+"size images by making a [[ikiwiki/WikiLink]] that points to the image, using "
+"this directive you can easily scale down an image for inclusion onto a page, "
+"providing a link to a full-size version."
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!img image1.jpg size=\"200x200\" alt=\"clouds\"]]\n"
+msgstr "\t\\[[!img image1.jpg size=\"200x200\" alt=\"skyer\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The image file will be searched for using the same rules as used to find the "
+"file pointed to by a [[ikiwiki/WikiLink]]."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The `size` parameter is optional, defaulting to full size. Note that the "
+"original image's aspect ratio is always preserved, even if this means making "
+"the image smaller than the specified size. You can also specify only the "
+"width or the height, and the other value will be calculated based on it: "
+"\"200x\", \"x200\""
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"You can also pass `alt`, `title`, `class`, `align` and `id` parameters. "
+"These are passed through unchanged to the html img tag. If you include a "
+"`caption` parameter, the caption will be displayed centered beneath the "
+"image."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The `link` parameter is used to control whether the scaled down image links "
+"to the full size version. By default it does; set \"link=somepage\" to link "
+"to another page instead, or \"link=no\" to disable the link, or "
+"\"link=http://url\" to link to a given url."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"You can also set default values that will be applied to all later images on "
+"the page, unless overridden. Useful when including many images on a page."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!img defaults size=200x200 alt=\"wedding photo\"]]\n"
+"\t\\[[!img photo1.jpg]]\n"
+"\t\\[[!img photo2.jpg]]\n"
+"\t\\[[!img photo3.jpg size=200x600]]\n"
+msgstr ""
+"\t\\[[!img defaults size=200x200 alt=\"bryllupsfoto\"]]\n"
+"\t\\[[!img photo1.jpg]]\n"
+"\t\\[[!img photo2.jpg]]\n"
+"\t\\[[!img photo3.jpg size=200x600]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/inline page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `inline` directive is supplied by the [[!iki plugins/inline "
+"desc=inline]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This is a directive that allows including one wiki page inside another. The "
+"most common use of inlining is generating blogs and RSS or Atom feeds."
+msgstr ""
+
+#. type: Plain text
+msgid "Example:"
+msgstr "Eksempel:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"blog/* and !*/Discussion\" show=\"10\" rootpage=\"blog\"]]\n"
+msgstr "\t\\[[!inline pages=\"blog/* and !*/Discussion\" show=\"10\" rootpage=\"blog\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Any pages that match the specified [[PageSpec]] (in the example, any "
+"[[SubPage]] of \"blog\") will be part of the blog, and the newest 10 of them "
+"will appear in the page. Note that if files that are not pages match the "
+"[[PageSpec]], they will be included in the feed using RSS enclosures, which "
+"is useful for podcasting."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The optional `rootpage` parameter tells the wiki that new posts to this blog "
+"should default to being [[SubPages|SubPage]] of \"blog\", and enables a form "
+"at the top of the blog that can be used to add new items."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"If you want your blog to have an archive page listing every post ever made "
+"to it, you can accomplish that like this:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"blog/* and !*/Discussion\" archive=\"yes\"]]\n"
+msgstr "\t\\[[!inline pages=\"blog/* and !*/Discussion\" archive=\"yes\"]]\n"
+
+#. type: Plain text
+msgid ""
+"You can even create an automatically generated list of all the pages on the "
+"wiki, with the most recently added at the top, like this:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"* and !*/Discussion\" archive=\"yes\"]]\n"
+msgstr "\t\\[[!inline pages=\"* and !*/Discussion\" archive=\"yes\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If you want to be able to add pages to a given blog feed by tagging them, "
+"you can do that too. To tag a page, just make it link to a page or pages "
+"that represent its tags. Then use the special `link()` [[PageSpec]] to match "
+"all pages that have a given tag:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"link(life)\"]]\n"
+msgstr "\t\\[[!inline pages=\"link(livet)\"]]\n"
+
+#. type: Plain text
+msgid "Or include some tags and exclude others:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!inline pages=\"link(debian) and !link(social)\"]]\n"
+msgstr "\t\\[[!inline pages=\"link(debian) and !link(venner)\"]]\n"
+
+#. type: Title ##
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Plain text
+msgid ""
+"There are many parameters you can use with the `inline` directive. These are "
+"the commonly used ones:"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`pages` - A [[PageSpec]] of the pages to inline."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`show` - Specify the maximum number of matching pages to inline. Default is "
+"10, unless archiving, when the default is to show all. Set to 0 to show all "
+"matching pages."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`archive` - If set to \"yes\", only list page titles and some metadata, not "
+"full contents."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`description` - Sets the description of the rss feed if one is generated. "
+"Defaults to the name of the wiki."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`skip` - Specify a number of pages to skip displaying. Can be useful to "
+"produce a feed that only shows archived pages."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`postform` - Set to \"yes\" to enable a form to post new pages to a blog."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`postformtext` - Set to specify text that is displayed in a postform."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`rootpage` - Enable the postform, and allows controling where newly posted "
+"pages should go, by specifiying the page that they should be a [[SubPage]] "
+"of."
+msgstr ""
+
+#. type: Plain text
+msgid "Here are some less often needed parameters:"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`actions` - If set to \"yes\" add links to the bottom of the inlined pages "
+"for editing and discussion (if they would be shown at the top of the page "
+"itself)."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`rss` - controls generation of an rss feed. If the wiki is configured to "
+"generate rss feeds by default, set to \"no\" to disable. If the wiki is "
+"configured to `allowrss`, set to \"yes\" to enable."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`atom` - controls generation of an atom feed. If the wiki is configured to "
+"generate atom feeds by default, set to \"no\" to disable. If the wiki is "
+"configured to `allowatom`, set to \"yes\" to enable."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`feeds` - controls generation of all types of feeds. Set to \"no\" to "
+"disable generating any feeds."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`emptyfeeds` - Set to \"no\" to disable generation of empty feeds. Has no "
+"effect if `rootpage` or `postform` is set."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`template` - Specifies the template to fill out to display each inlined "
+"page. By default the `inlinepage` template is used, while the `archivepage` "
+"template is used for archives. Set this parameter to use some other, custom "
+"template, such as the `titlepage` template that only shows post titles or "
+"the `microblog` template, optimised for microblogging. Note that you should "
+"still set `archive=yes` if your custom template does not include the page "
+"content."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`raw` - Rather than the default behavior of creating a blog, if raw is set "
+"to \"yes\", the page will be included raw, without additional markup around "
+"it, as if it were a literal part of the source of the inlining page."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`sort` - Controls how inlined pages are sorted. The default, \"age\" is to "
+"sort newest created pages first. Setting it to \"title\" will sort pages by "
+"title, and \"mtime\" sorts most recently modified pages first. If [[!cpan "
+"Sort::Naturally]] is installed, `sort` can be set to \"title_natural\" to "
+"sort by title with numbers treated as such (\"1 2 9 10 20\" instead of \"1 "
+"10 2 20 9\")."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`reverse` - If set to \"yes\", causes the sort order to be reversed."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`feedshow` - Specify the maximum number of matching pages to include in the "
+"rss/atom feeds. The default is the same as the `show` value above."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`feedonly` - Only generate the feed, do not display the pages inline on the "
+"page."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`quick` - Build archives in quick mode, without reading page contents for "
+"metadata. By default, this also turns off generation of any feeds."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`timeformat` - Use this to specify how to display the time or date for pages "
+"in the blog. The format string is passed to the strftime(3) function."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`feedpages` - A [[PageSpec]] of inlined pages to include in the rss/atom "
+"feeds. The default is the same as the `pages` value above, and only pages "
+"matched by that value are included, but some of those can be excluded by "
+"specifying a tighter [[PageSpec]] here."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`guid` - If a URI is given here (perhaps a UUID prefixed with `urn:uuid:`), "
+"the Atom feed will have this as its `<id>`. The default is to use the URL of "
+"the page containing the `inline` directive."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`feedfile` - Can be used to change the name of the file generated for the "
+"feed. This is particularly useful if a page contains multiple feeds. For "
+"example, set \"feedfile=feed\" to cause it to generate `page/feed.atom` and/"
+"or `page/feed.rss`. This option is not supported if the wiki is configured "
+"not to use `usedirs`."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
+
+#. type: Plain text
+msgid ""
+"A related directive is the [[ikiwiki/directive/edittemplate]] directive, "
+"which allows default text for a new page to be specified."
+msgstr ""
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/linkmap page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `linkmap` directive is supplied by the [[!iki plugins/linkmap "
+"desc=linkmap]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive uses [graphviz](http://www.graphviz.org/) to generate a graph "
+"showing the links between a set of pages in the wiki. Example usage:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!linkmap pages=\"* and !blog/* and !*/Discussion\"]]\n"
+msgstr "\t\\[[!linkmap pages=\"* and !blog/* and !*/Discussion\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Only links between mapped pages will be shown; links pointing to or from "
+"unmapped pages will be omitted. If the pages to include are not specified, "
+"the links between all pages (and other files) in the wiki are mapped. For "
+"best results, only a small set of pages should be mapped, since otherwise "
+"the map can become very large, unwieldy, and complicated. Also, the map is "
+"rebuilt whenever one of the mapped pages is changed, which can make the wiki "
+"a bit slow."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Here are descriptions of all the supported parameters to the `linkmap` "
+"directive:"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`pages` - A [[ikiwiki/PageSpec]] of the pages to map."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`height`, `width` - Limit the size of the map to a given height and width, "
+"in inches. Both must be specified for the limiting to take effect, otherwise "
+"the map's size is not limited."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/listdirectives page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `listdirectives` directive is supplied by the [[!iki plugins/"
+"listdirectives desc=listdirectives]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive generates a list of available [[directives|ikiwiki/"
+"directive]]."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!listdirectives]]\n"
+msgstr "\t\\[[!listdirectives]]\n"
+
+#. type: Plain text
+msgid ""
+"There is one optional keyword argument, `generated`. Normally the "
+"`listdirectives` directive will list all built in directives and directives "
+"directly registered by plugins. With this keyword, `listdirectives` will "
+"also list directives generated later. For example, all [[shortcuts]] are "
+"directives generated in turn by the `shortcut` directive. They will only be "
+"listed if the `generated` argument is supplied."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " \\[[!listdirectives generated]]\n"
+msgstr " \\[[!listdirectives generated]]\n"
+
+#. type: Plain text
+msgid ""
+"This extended list is often quite long, and often contains many undocumented "
+"directives."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/map page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `map` directive is supplied by the [[!iki plugins/map desc=map]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive generates a hierarchical page map for the wiki. Example usage:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!map pages=\"* and !blog/* and !*/Discussion\"]]\n"
+msgstr "\t\\[[!map pages=\"* and !blog/* and !*/Discussion\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If the pages to include are not specified, all pages (and other files) in "
+"the wiki are mapped."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"By default, the names of pages are shown in the map. The `show` parameter "
+"can be used to show the titles or descriptions of pages instead (as set by "
+"the [[meta]] directive). For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!map pages=\"* and !blog/* and !*/Discussion\" show=title]]\n"
+msgstr "\t\\[[!map pages=\"* and !blog/* and !*/Discussion\" show=title]]\n"
+
+#. type: Plain text
+msgid ""
+"Hint: To limit the map to displaying pages less than a certain level deep, "
+"use a [[ikiwiki/PageSpec]] like this: `pages=\"* and !*/*/*\"`"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/meta page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `meta` directive is supplied by the [[!iki plugins/meta desc=meta]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows inserting arbitrary metadata into the source of a "
+"page. Enter the metadata as follows:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!meta field=\"value\"]]\n"
+"\t\\[[!meta field=\"value\" param=\"value\" param=\"value\"]]\n"
+msgstr ""
+"\t\\[[!meta felt=\"værdi\"]]\n"
+"\t\\[[!meta felt=\"værdi\" param=\"værdi\" param=\"værdi\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The first form sets a given field to a given value, while the second form "
+"also specifies some additional sub-parameters."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The field values are treated as HTML entity-escaped text, so you can include "
+"a quote in the text by writing `"` and so on."
+msgstr ""
+
+#. type: Plain text
+msgid "Supported fields:"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "title"
+msgstr "title"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Overrides the title of the page, which is generally the same as the\n"
+" page name.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Note that if the title is overridden, a \"title_overridden\" variable will\n"
+" be set to a true value in the template; this can be used to format things\n"
+" differently in this case.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "license"
+msgstr "license"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies a license for the page, for example, \"GPL\". Can contain\n"
+" WikiLinks and arbitrary markup.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "copyright"
+msgstr "copyright"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies the copyright of the page, for example, \"Copyright 2007 by\n"
+" Joey Hess\". Can contain WikiLinks and arbitrary markup.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "author"
+msgstr "author"
+
+#. type: Plain text
+#, no-wrap
+msgid " Specifies the author of a page.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "authorurl"
+msgstr "authorurl"
+
+#. type: Plain text
+#, no-wrap
+msgid " Specifies an url for the author of a page.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "description"
+msgstr "description"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies a \"description\" of the page. You could use this to provide\n"
+" a summary, for example, to be picked up by the [[map]] directive.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "permalink"
+msgstr "permalink"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies a permanent link to the page, if different than the page\n"
+" generated by ikiwiki.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "date"
+msgstr "date"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies the creation date of the page. The date can be entered in\n"
+" nearly any format, since it's parsed by [[!cpan TimeDate]].\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "stylesheet"
+msgstr "stylesheet"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Adds a stylesheet to a page. The stylesheet is treated as a wiki link to\n"
+" a `.css` file in the wiki, so it cannot be used to add links to external\n"
+" stylesheets. Example:\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!meta stylesheet=somestyle rel=\"alternate stylesheet\"\n"
+"\ttitle=\"somestyle\"]]\n"
+msgstr ""
+"\t\\[[!meta stylesheet=somestyle rel=\"alternate stylesheet\"\n"
+"\ttitle=\"etstilark\"]]\n"
+
+#. type: Bullet: '* '
+msgid "openid"
+msgstr "openid"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Adds html <link> tags to perform OpenID delegation to an external\n"
+" OpenID server. This lets you use an ikiwiki page as your OpenID.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" By default this will delegate for both `openid` and `openid2`. To only\n"
+" delegate for one, add a parameter such as `delegate=openid`.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" An optional `xrds-location`\n"
+" parameter lets you specify the location of any [eXtensible Resource\n"
+" DescriptorS](http://www.windley.com/archives/2007/05/using_xrds.shtml).\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " Example:\n"
+msgstr " Eksempel:\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\\\[[!meta openid=\"http://joeyh.myopenid.com/\"\n"
+"\tserver=\"http://www.myopenid.com/server\"\n"
+"\txrds-location=\"http://www.myopenid.com/xrds?username=joeyh.myopenid.com\"\"]]\n"
+msgstr ""
+"\t\\\\[[!meta openid=\"http://joeyh.myopenid.com/\"\n"
+"\tserver=\"http://www.myopenid.com/server\"\n"
+"\txrds-location=\"http://www.myopenid.com/xrds?username=joeyh.myopenid.com\"\"]]\n"
+
+#. type: Bullet: '* '
+msgid "link"
+msgstr "link"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies a link to another page. This can be used as a way to make the\n"
+" wiki treat one page as linking to another without displaying a user-visible\n"
+" [[ikiwiki/WikiLink]]:\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " \\[[!meta link=otherpage]]\n"
+msgstr " \\[[!meta link=enandenside]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid " It can also be used to insert a html <link> tag. For example:\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " \\[[!meta link=\"http://joeyh.myopenid.com/\" rel=\"openid.delegate\"]]\n"
+msgstr " \\[[!meta link=\"http://joeyh.myopenid.com/\" rel=\"openid.delegate\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" However, this latter syntax won't be allowed if the \n"
+" [[!iki plugins/htmlscrubber desc=htmlscrubber]] plugin is enabled, since it can be used to\n"
+" insert unsafe content.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "redir"
+msgstr "redir"
+
+#. type: Plain text
+#, no-wrap
+msgid " Causes the page to redirect to another page in the wiki.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " \t\\[[!meta redir=otherpage]]\n"
+msgstr " \t\\[[!meta redir=otherpage]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Optionally, a delay (in seconds) can be specified. The default is to\n"
+" redirect without delay.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " It can also be used to redirect to an external url. For example:\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " \t\\[[!meta redir=\"http://example.com/\"]]\n"
+msgstr " \t\\[[!meta redir=\"http://eksempel.dk/\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" For both cases, an anchor to jump to inside the destination page may also be\n"
+" specified using the common `#ANCHOR` syntax.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "robots"
+msgstr "robots"
+
+#. type: Plain text
+#, no-wrap
+msgid " Causes the robots meta tag to be written:\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " \\[[!meta robots=\"index, nofollow\"]]\n"
+msgstr " \\[[!meta robots=\"index, nofollow\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Valid values for the attribute are: \"index\", \"noindex\", \"follow\", and\n"
+" \"nofollow\". Multiple comma-separated values are allowed, but obviously only\n"
+" some combinations make sense. If there is no robots meta tag, \"index,\n"
+" follow\" is used as the default.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid " The value is escaped, but its contents are not otherwise checked.\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "guid"
+msgstr "guid"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies a globally unique ID for a page. This guid should be a URI\n"
+" (in particular, it can be `urn:uuid:` followed by a UUID, as per\n"
+" [[!rfc 4122]]), and it will be used to identify the page's entry in RSS\n"
+" and Atom feeds. If not given, the default is to use the page's URL as its\n"
+" guid.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" This is mostly useful when a page has moved, to keep the guids for\n"
+" pages unchanged and avoid_flooding_aggregators\n"
+" (see [[!iki tips/howto_avoid_flooding_aggregators]]).\n"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "updated"
+msgstr "updated"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Specifies a fake modification time for a page, to be output into RSS and\n"
+" Atom feeds. This is useful to avoid flooding aggregators that sort by\n"
+" modification time, like Planet: for instance, when editing an old blog post\n"
+" to add tags, you could set `updated` to be one second later than the original\n"
+" value. The date/time can be given in any format that\n"
+" [[!cpan TimeDate]] can understand, just like the `date` field.\n"
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"If the field is not one of the above predefined fields, the metadata will be "
+"written to the generated html page as a <meta> header. However, this "
+"won't be allowed if the [[!iki plugins/htmlscrubber desc=htmlscrubber]] "
+"plugin is enabled, since it can be used to insert unsafe content."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/more page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `more` directive is supplied by the [[!iki plugins/more desc=more]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive provides a way to have a \"more\" link on a post in a blog, "
+"that leads to the full version of the page. Use it like this:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!more linktext=\"click for more\" text=\"\"\"\n"
+msgstr "\t\\[[!more linktext=\"klik for mere\" text=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tThis is the rest of my post. Not intended for people catching up on\n"
+"\ttheir blogs at 30,000 feet. Because I like to make things\n"
+"\tdifficult.\n"
+msgstr ""
+
+#. type: Plain text
+msgid "If the `linktext` parameter is omitted it defaults to just \"more\"."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Note that you can accomplish something similar using a [[toggle]] instead."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/orphans page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `orphans` directive is supplied by the [[!iki plugins/orphans "
+"desc=orphans]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive generates a list of possibly orphaned pages -- pages that no "
+"other page links to. Example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!orphans pages=\"* and !blog/*\"]]\n"
+msgstr "\t\\[[!orphans pages=\"* and !blog/*\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The optional parameter \"pages\" can be a [[ikiwiki/PageSpec]] specifying "
+"the pages to check for orphans, default is search them all."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Note that it takes backlinks into account, but does not count inlining a "
+"page as linking to it, so will generally count many blog-type pages as "
+"orphans."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/pagecount page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `pagecount` directive is supplied by the [[!iki plugins/pagecount "
+"desc=pagecount]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid "This directive counts pages currently in the wiki. Example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!pagecount pages=\"*\"]]\n"
+msgstr "\t\\[[!pagecount pages=\"*\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The optional parameter \"pages\" can be a [[ikiwiki/PageSpec]] specifying "
+"the pages to count, default is to count them all."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/pagestats page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `pagestats` directive is supplied by the [[!iki plugins/pagestats "
+"desc=pagestats]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive can generate stats about how pages link to each other. It can "
+"produce either a tag cloud, or a table counting the number of links to each "
+"page."
+msgstr ""
+
+#. type: Plain text
+msgid "Here's how to use it to create a [[tag]] cloud:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!pagestats pages=\"tags/*\"]]\n"
+msgstr "\t\\[[!pagestats pages=\"tags/*\"]]\n"
+
+#. type: Plain text
+msgid "And here's how to create a table of all the pages on the wiki:"
+msgstr "Og sådan her dannes en tabel over alle sider i wikien:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!pagestats style=\"table\"]]\n"
+msgstr "\t\\[[!pagestats style=\"table\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/pagetemplate page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `pagetemplate` directive is supplied by the [[!iki plugins/pagetemplate "
+"desc=pagetemplate]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows a page to be created using a different wikitemplates. "
+"The page text is inserted into the template, so the template controls the "
+"overall look and feel of the wiki page. This is in contrast to the [[ikiwiki/"
+"directive/template]] directive, which allows inserting templates _into_ the "
+"body of a page."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive can only reference templates that are already installed by "
+"the system administrator, typically into the `/usr/share/ikiwiki/templates` "
+"directory. Example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!pagetemplate template=\"my_fancy.tmpl\"]]\n"
+msgstr "\t\\[[!pagetemplate template=\"min_smarte.tmpl\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/paste page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta redir=/ikiwiki/directive/cutpaste]]\n"
+msgstr "[[!meta redir=/ikiwiki/directive/cutpaste]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/ping page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `ping` directive is supplied by the [[!iki plugins/pinger desc=pinger]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows ikiwiki to be configured to hit a URL each time it "
+"updates the wiki. One way to use this is in conjunction with the [[!iki "
+"plugins/pingee desc=pingee]] plugin to set up a loosely coupled mirror "
+"network, or a branched version of a wiki. By pinging the mirror or branch "
+"each time the main wiki changes, it can be kept up-to-date."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" \\[[!ping from=\"http://mywiki.com/\"\n"
+" to=\"http://otherwiki.com/ikiwiki.cgi?do=ping\"]]\n"
+msgstr ""
+" \\[[!ping from=\"http://mywiki.com/\"\n"
+" to=\"http://otherwiki.com/ikiwiki.cgi?do=ping\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The \"from\" parameter must be identical to the url of the wiki that is "
+"doing the pinging. This is used to prevent ping loops."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The \"to\" parameter is the url to ping. The example shows how to ping "
+"another ikiwiki instance."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/poll page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `poll` directive is supplied by the [[!iki plugins/poll desc=poll]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows you to create online polls in the wiki. Here's an "
+"example use:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!poll 0 \"red\" 0 \"green\" 0 \"blue\"]]\n"
+msgstr "\t\\[[!poll 0 \"rød\" 0 \"grøn\" 0 \"blå\"]]\n"
+
+#. type: Plain text
+msgid ""
+"The numbers indicate how many users voted for that choice. When a user votes "
+"for a choice in the poll, the page is modified and the number incremented."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"While some basic precautions are taken to prevent users from accidentially "
+"voting twice, this sort of poll should not be counted on to be very "
+"accurate; all the usual concerns about web based polling apply. Unless the "
+"page that the poll is in is locked, users can even edit the page and change "
+"the numbers!"
+msgstr ""
+
+#. type: Plain text
+msgid "Parameters:"
+msgstr "Parametre:"
+
+#. type: Bullet: '* '
+msgid ""
+"`open` - Whether voting is still open. Set to \"no\" to close the poll to "
+"voting."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`total` - Show total number of votes at bottom of poll. Default is \"yes\"."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`percent` - Whether to display percents. Default is \"yes\"."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/polygen page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `polygen` directive is supplied by the [[!iki plugins/polygen "
+"desc=polygen]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows inserting text generated by polygen into a wiki page. "
+"For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!polygen grammar=\"genius\"]]\n"
+msgstr "\t\\[[!polygen grammar=\"genius\"]]\n"
+
+#. type: Plain text
+msgid ""
+"It's also possible to specify a starting nonterminal for the grammar by "
+"including `symbol=\"text\"` in the directive."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/postsparkline page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `postsparkline` directive is supplied by the [[!iki plugins/"
+"postsparkline desc=postsparkline]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive uses the [[!iki plugins/sparkline desc=sparkline]] plugin to "
+"create a [[sparkline]] of statistics about a set of pages, such as posts to "
+"a blog."
+msgstr ""
+
+#. type: Title #
+#, no-wrap
+msgid "examples"
+msgstr "eksempler"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tPost interval: \n"
+"\t\\[[!postsparkline pages=\"blog/* and !*/Discussion\" max=100\n"
+"\tformula=interval style=bar barwidth=2 barspacing=1 height=13]]\n"
+msgstr ""
+"\tBidragsinterval: \n"
+"\t\\[[!postsparkline pages=\"blog/* and !*/Discussion\" max=100\n"
+"\tformula=interval style=bar barwidth=2 barspacing=1 height=13]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tPosts per month this year: \n"
+"\t\\[[!postsparkline pages=\"blog/* and !*/Discussion\" max=12\n"
+"\tformula=permonth style=bar barwidth=2 barspacing=1 height=13]]\n"
+msgstr ""
+"\tBidrag per måned dette år: \n"
+"\t\\[[!postsparkline pages=\"blog/* and !*/Discussion\" max=12\n"
+"\tformula=permonth style=bar barwidth=2 barspacing=1 height=13]]\n"
+
+#. type: Title #
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Plain text
+msgid ""
+"All options aside fron the `pages`, `max`, `formula`, `time`, and `color` "
+"options are the same as in [[sparkline]] directive."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"You don't need to specify any data points (though you can if you want to). "
+"Instead, data points are automatically generated based on the creation times "
+"of pages matched by the specified `pages` [[ikiwiki/PageSpec]]. A maximum of "
+"`max` data points will be generated."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The `formula` parameter controls the formula used to generate data points. "
+"Available forumlae:"
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`interval` - The height of each point represents how long it has been since "
+"the previous post."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`perday` - Each point represents a day; the height represents how many posts "
+"were made that day."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`permonth` - Each point represents a month; the height represents how many "
+"posts were made that month."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`peryear` - Each point represents a day; the height represents how many "
+"posts were made that year."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The `time` parameter has a default value of \"ctime\", since forumae use the "
+"creation times of pages by default. If you instead want them to use the "
+"modification times of pages, set it to \"mtime\"."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"To change the color used to draw the sparkline, use the `color` parameter. "
+"For example, \"color=red\"."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/progress page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `progress` directive is supplied by the [[!iki plugins/progress "
+"desc=progress]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid "This directive generates a progress bar."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"There are two possible parameter sets. The first is a single parameter "
+"\"percent\" which holds a percentage figure of how complete the progress bar "
+"is."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The second possible set of parameters is a pair of [[ikiwiki/PageSpec]]s, "
+"`totalpages` and `donepages`. The directive counts the number of pages in "
+"each pagespec and shows the percentage of the total pages that are done."
+msgstr ""
+
+#. type: Plain text
+msgid "For example, to show what percentage of pages have discussion pages:"
+msgstr "Eksempelvis at vise procentdel af sider med diskussionssider:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!progress totalpages=\"* and !*/Discussion\" donepages=\"*/Discussion\"]]\n"
+msgstr "\t\\[[!progress totalpages=\"* and !*/Discussion\" donepages=\"*/Discussion\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/shortcut page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-19 23:45+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `shortcut` directive is supplied by the [[!iki plugins/shortcut "
+"desc=shortcut]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows external links to commonly linked to sites to be made "
+"more easily using shortcuts."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The available shortcuts are defined on the [[shortcuts]] page in the wiki. "
+"The `shortcut` directive can only be used on that page."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/sparkline page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `sparkline` directive is supplied by the [[!iki plugins/sparkline "
+"desc=sparkline]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows for embedding sparklines into wiki pages. A sparkline "
+"is a small word-size graphic chart, that is designed to be displayes "
+"alongside text."
+msgstr ""
+
+#. type: Title #
+#, no-wrap
+msgid "examples"
+msgstr "eksempler"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!sparkline 1 3 5 -3 10 0 width=40 height=16\n"
+"\tfeaturepoint=\"4,-3,red,3\" featurepoint=\"5,10,green,3\"]]\n"
+msgstr ""
+"\t\\[[!sparkline 1 3 5 -3 10 0 width=40 height=16\n"
+"\tfeaturepoint=\"4,-3,red,3\" featurepoint=\"5,10,green,3\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This creates a simple line graph, graphing several points. It will be drawn "
+"40 pixels wide and 16 pixels high. The high point in the line has a green "
+"marker, and the low point has a red marker."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!sparkline 1 -1(red) 1 -1(red) 1 1 1 -1(red) -1(red) style=bar barwidth=2\n"
+"\tbarspacing=1 height=13]]\n"
+msgstr ""
+"\t\\[[!sparkline 1 -1(red) 1 -1(red) 1 1 1 -1(red) -1(red) style=bar barwidth=2\n"
+"\tbarspacing=1 height=13]]\n"
+
+#. type: Plain text
+msgid ""
+"This more complex example generates a bar graph. The bars are 2 pixels "
+"wide, and separated by one pixel, and the graph is 13 pixels tall. Width is "
+"determined automatically for bar graphs. The points with negative values are "
+"colored red, instead of the default black."
+msgstr ""
+
+#. type: Title #
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Plain text
+msgid ""
+"The form for the data points is \"x,y\", or just \"y\" if the x values don't "
+"matter. Bar graphs can also add \"(color)\" to specify a color for that bar."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The following named parameters are recognised. Most of these are the same as "
+"those used by the underlying sparkline library, which is documented in more "
+"detail in [its wiki](http://sparkline.wikispaces.com/usage)."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`style` - Either \"line\" (the default) or \"bar\"."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`width` - Width of the graph in pixels. Only needed for line graphs."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`height` - Height of the graph in pixels. Defaults to 16."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`barwidth` - Width of bars in a bar graph. Default is 1 pixel."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`barspacing` - Spacing between bars in a bar graph, in pixels. Default is 1 "
+"pixel."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`ymin`, `ymax` - Minimum and maximum values for the Y axis. This is normally "
+"calculated automatically, but can be explicitly specified to get the same "
+"values for multiple related graphs."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`featurepoint` - Adds a circular marker to a line graph, with optional text. "
+"This can be used to label significant points."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" The value is a comma-delimited list of parameters specifying the feature\n"
+" point: X value, Y value, color name, circle diameter, text (optional),\n"
+" and text location (optional). Example: `featurepoint=\"3,5,blue,3\"`\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+" Available values for the text location are: \"top\", \"right\", \"bottom\", and\n"
+" \"left\".\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/table page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `table` directive is supplied by the [[!iki plugins/table desc=table]] "
+"plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive can build HTML tables from data in CSV (comma-separated "
+"values) or DSV (delimiter-separated values) format."
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "examples"
+msgstr "eksempler"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!table data=\"\"\"\n"
+msgstr "\t\\[[!table data=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tCustomer|Amount\n"
+"\tFulanito|134,34\n"
+"\tMenganito|234,56\n"
+"\tMenganito|234,56\n"
+msgstr ""
+"\tKunde|Mængde\n"
+"\tFulanito|134,34\n"
+"\tMenganito|234,56\n"
+"\tMenganito|234,56\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!table class=\"book_record\" format=csv file=\"data/books/record1\"]]\n"
+msgstr "\t\\[[!table class=\"book_record\" format=csv file=\"data/books/record1\"]]\n"
+
+#. type: Plain text
+msgid "In this second example the `record1` page should be similar to:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\"Title\",\"Perl Best Practices\"\n"
+"\t\"Author\",\"Damian Conway\"\n"
+"\t\"Publisher\",\"O’Reilly\"\n"
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"To make a cell span multiple columns, follow it with one or more empty "
+"cells. For example:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tleft||right|\n"
+"\ta|b|c|d\n"
+"\tthis cell spans 4 columns|||\n"
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "usage"
+msgstr "brug"
+
+#. type: Bullet: '* '
+msgid "`data` - Values for the table."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid "`file` - A file in the wiki containing the data."
+msgstr ""
+
+#. type: Bullet: '* '
+msgid ""
+"`format` - The format of the data, either \"csv\", \"dsv\", or \"auto\" (the "
+"default)."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"* `delimiter` - The character used to separate fields. By default,\n"
+" DSV format uses a pipe (`|`), and CSV uses a comma (`,`).\n"
+"* `class` - A CSS class for the table html element.\n"
+"* `header` - By default, or if set to \"row\", the first data line is used\n"
+" as the table header. Set it to \"no\" to make a table without a header, or\n"
+" \"column\" to make the first column be the header.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/tag page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `tag` and `taglink` directives are supplied by the [[!iki plugins/tag "
+"desc=tag]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid "These directives allow tagging pages. List tags as follows:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!tag tech life linux]]\n"
+msgstr "\t\\[[!tag teknik livet linux]]\n"
+
+#. type: Plain text
+msgid ""
+"The tags work the same as if you had put a (hidden) [[ikiwiki/WikiLink]] on "
+"the page for each tag, so you can use a [[ikiwiki/PageSpec]] match all pages "
+"that are tagged with a given tag, for example. The tags will also show up on "
+"blog entries and at the bottom of the tagged pages, as well as in RSS and "
+"Atom feeds."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"If you want a visible [[ikiwiki/WikiLink]] along with the tag, use taglink "
+"instead:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!taglink foo]]\n"
+"\t\\[[!taglink tagged_as_foo|foo]]\n"
+msgstr ""
+"\t\\[[!taglink foo]]\n"
+"\t\\[[!taglink mærket_af_som_foo|foo]]\n"
+
+#. type: Plain text
+msgid ""
+"Note that if the wiki is configured to use a tagbase, then the tags will be "
+"located under a base directory, such as \"tags/\". This is a useful way to "
+"avoid having to write the full path to tags, if you want to keep them "
+"grouped together out of the way."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Bear in mind that specifying a tagbase means you will need to incorporate it "
+"into the `link()` [[ikiwiki/PageSpec]] you use: e.g., if your tagbase is "
+"`tag`, you would match pages tagged \"foo\" with `link(tag/foo)`."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"If you want to override the tagbase for a particular tag, you can use "
+"something like this:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!tag ./foo]]\n"
+"\t\\[[!taglink /foo]]\n"
+msgstr ""
+"\t\\[[!tag ./foo]]\n"
+"\t\\[[!taglink /foo]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/tagline page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta redir=/ikiwiki/directive/tag]]\n"
+msgstr "[[!meta redir=/ikiwiki/directive/tag]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/template page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `template` directive is supplied by the [[!iki plugins/template "
+"desc=template]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"[[Templates]] are files that can be filled out and inserted into pages in "
+"the wiki, by using the template directive. The directive has an `id` "
+"parameter that identifies the template to use. The remaining parameters are "
+"used to fill out the template."
+msgstr ""
+
+#. type: Plain text
+msgid "Example:"
+msgstr "Eksempel:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!template id=note text=\"\"\"Here is the text to insert into my note.\"\"\"]]\n"
+msgstr "\t\\[[!template id=note text=\"\"\"Her er teksten til at sætte ind i min note.\"\"\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This fills out the `note` template, filling in the `text` field with the "
+"specified value, and inserts the result into the page."
+msgstr ""
+"Dette udfylder `note`-skabelonen, med `text`-feltet udfyldt med den angivne "
+"værdi, og indsætter resultatet på siden."
+
+#. type: Plain text
+msgid ""
+"For a list of available templates, and details about how to create more, see "
+"the [[templates]] page."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/testpagespec page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `testpagespec` directive is supplied by the [[!iki plugins/testpagespec "
+"desc=testpagespec]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"This directive allows testing a [[ikiwiki/PageSpec]] to see if it matches a "
+"page, and to see the part that matches, or causes the match to fail."
+msgstr ""
+
+#. type: Plain text
+msgid "Example uses:"
+msgstr "Eksempelbrug:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!testpagespec pagespec=\"foopage and barpage\" match=\"foopage\"]]\n"
+msgstr "\t\\[[!testpagespec pagespec=\"foopage and barpage\" match=\"foopage\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This will print out something like \"no match: barpage does not match foopage"
+"\", highlighting which part of the [[ikiwiki/PageSpec]] is causing the match "
+"to fail."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!testpagespec pagespec=\"foopage or !bar*\" match=\"barpage\"]]\n"
+msgstr "\t\\[[!testpagespec pagespec=\"foopage or !bar*\" match=\"barpage\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This will print out something like \"no match: bar* matches barpage\", since "
+"the part of the [[ikiwiki/PageSpec]] that fails is this negated match."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!testpagespec pagespec=\"foopage or barpage\" match=\"barpage\"]]\n"
+msgstr "\t\\[[!testpagespec pagespec=\"foopage or barpage\" match=\"barpage\"]]\n"
+
+#. type: Plain text
+msgid ""
+"This will print out something like \"match: barpage matches barpage\", "
+"indicating the part of the [[ikiwiki/PageSpec]] that caused it to match."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/teximg page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `teximg` directive is supplied by the [[!iki plugins/teximg "
+"desc=teximg]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid "This directive renders LaTeX formulas into images."
+msgstr ""
+
+#. type: Title ##
+#, no-wrap
+msgid "examples"
+msgstr "eksempler"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!teximg code=\"\\frac{1}{2}\"]]\n"
+"\t\\[[!teximg code=\"E = - \\frac{Z^2 \\cdot \\mu \\cdot e^4}{32\\pi^2 \\epsilon_0^2 \\hbar^2 n^2}\" ]]\n"
+msgstr ""
+
+#. type: Plain text
+msgid "To scale the image, use height=x:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\t\\[[!teximg code=\"\\frac{1}{2}\" height=\"17\"]]\n"
+"\t\\[[!teximg code=\"\\frac{1}{2}\" height=\"8\"]]\n"
+msgstr ""
+"\t\\[[!teximg code=\"\\frac{1}{2}\" height=\"17\"]]\n"
+"\t\\[[!teximg code=\"\\frac{1}{2}\" height=\"8\"]]\n"
+
+#. type: Plain text
+msgid ""
+"If no height is chosen the default height 12 is used. Valid heights are: 8, "
+"9, 10, 11, 12, 14, 17, 20. If another height is entered, the closest "
+"available height is used."
+msgstr ""
+
+#. type: Plain text
+msgid "To add an alt text to the image, use alt=\"text\":"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!teximg code=\"\\frac{1}{2}\" alt=\"1/2\"]]\n"
+msgstr "\t\\[[!teximg code=\"\\frac{1}{2}\" alt=\"1/2\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/toc page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `toc` directive is supplied by the [[!iki plugins/toc desc=toc]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid "Add a table of contents to a page:"
+msgstr "Tilføje en indholdsfortegnelse til en side:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!toc ]]\n"
+msgstr "\t\\[[!toc ]]\n"
+
+#. type: Plain text
+msgid ""
+"The table of contents will be automatically generated based on the headers "
+"of the page. By default only the largest headers present on the page will be "
+"shown; to control how many levels of headers are shown, use the `levels` "
+"parameter:"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!toc levels=2]]\n"
+msgstr "\t\\[[!toc levels=2]]\n"
+
+#. type: Plain text
+msgid ""
+"The toc directive will take the level of the first header as the topmost "
+"level, even if there are higher levels seen later in the file."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The table of contents will be created as an ordered list. If you want an "
+"unordered list instead, you can change the list-style in your local style "
+"sheet."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/toggle page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `toggle` and `toggleable` directives are supplied by the [[!iki plugins/"
+"toggle desc=toggle]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"With these directives you can create links on pages that, when clicked, "
+"toggle display of other parts of the page."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"It uses javascript to accomplish this; browsers without javascript will "
+"always see the full page content."
+msgstr ""
+
+#. type: Plain text
+msgid "Example use:"
+msgstr "Eksempler på brug:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!toggle id=\"ipsum\" text=\"show\"]]\n"
+msgstr "\t\\[[!toggle id=\"ipsum\" text=\"vis\"]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!toggleable id=\"ipsum\" text=\"\"\"\n"
+msgstr "\t\\[[!toggleable id=\"ipsum\" text=\"\"\"\n"
+
+#. type: Plain text
+#, no-wrap
+msgid ""
+"\tLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\n"
+"\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n"
+"\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n"
+"\taliquip ex ea commodo consequat.\n"
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "\t[[!toggle id=\"ipsum\" text=\"hide\"]]\n"
+msgstr "\t[[!toggle id=\"ipsum\" text=\"skjul\"]]\n"
+
+#. type: Plain text
+msgid ""
+"Note that you can include wiki markup in the toggleable text, including even "
+"additional toggles, as shown in the above example."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Also, the toggle and the togglable definitions do not need to be next to "
+"each other, but can be located anywhere on the page. There can also be "
+"mutiple toggles that all toggle a single togglable."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"The id has a default value of \"default\", so can be omitted in simple cases."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"If you'd like a toggleable to be displayed by default, and toggle to hidden, "
+"then pass a parameter \"open=yes\" when setting up the toggleable."
+msgstr ""
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/toggleable page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta redir=/ikiwiki/directive/toggle]]\n"
+msgstr "[[!meta redir=/ikiwiki/directive/toggle]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of directives/ikiwiki/directive/version page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-19 23:45+0200\n"
+"PO-Revision-Date: 2009-07-23 00:06+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"The `version` directive is supplied by the [[!iki plugins/version "
+"desc=version]] plugin."
+msgstr ""
+
+#. type: Plain text
+msgid "This directive allows inserting the version of ikiwiki onto a page."
+msgstr ""
+
+#. type: Plain text
+msgid ""
+"Whenever ikiwiki is upgraded to a new version, the page will be rebuilt, "
+"updating the version number."
+msgstr ""
+
+#. type: Plain text
+msgid "Use is simple:"
+msgstr "Brug er simpelt:"
+
+#. type: Plain text
+#, no-wrap
+msgid "\t\\[[!version ]]\n"
+msgstr "\t\\[[!version ]]\n"
+
+#. type: Plain text
+#, no-wrap
+msgid "[[!meta robots=\"noindex, follow\"]]\n"
+msgstr "[[!meta robots=\"noindex, follow\"]]\n"
--- /dev/null
+# Danish translation of smiley/smileys page for ikiwiki.
+# Copyright (C) 2008-2009 Jonas Smedegaard <dr@jones.dk>
+# This file is distributed under the same license as the ikiwiki package.
+# Jonas Smedegaard <dr@jones.dk>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ikiwiki 3.15\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-07-22 11:17+0300\n"
+"PO-Revision-Date: 2009-07-22 21:28+0200\n"
+"Last-Translator: Jonas Smedegaard <dr@jones.dk>\n"
+"Language-Team: None\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Danish\n"
+"X-Poedit-Country: DENMARK\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+#. type: Plain text
+msgid ""
+"This page is used to control what smileys are supported by the wiki. Just "
+"write the text of a smiley to display it."
+msgstr ""
+"Denne side bruges til at styre hvilke smileys denne wiki understøtter. Skriv "
+"blot smiley-teksten for at vise den."
+
+#. type: Bullet: '* '
+msgid "\\\\:)\t[[smileys/smile.png]]"
+msgstr "\\\\:)\t[[smileys/smile.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-)\t[[smileys/smile.png]]"
+msgstr "\\\\:-)\t[[smileys/smile.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:D\t[[smileys/biggrin.png]]"
+msgstr "\\\\:D\t[[smileys/biggrin.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-D\t[[smileys/biggrin.png]]"
+msgstr "\\\\:-D\t[[smileys/biggrin.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\B)\t[[smileys/smile2.png]]"
+msgstr "\\\\B)\t[[smileys/smile2.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\B-)\t[[smileys/smile2.png]]"
+msgstr "\\\\B-)\t[[smileys/smile2.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:))\t[[smileys/smile3.png]]"
+msgstr "\\\\:))\t[[smileys/smile3.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-))\t[[smileys/smile3.png]]"
+msgstr "\\\\:-))\t[[smileys/smile3.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\;)\t[[smileys/smile4.png]]"
+msgstr "\\\\;)\t[[smileys/smile4.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\;-)\t[[smileys/smile4.png]]"
+msgstr "\\\\;-)\t[[smileys/smile4.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:\\\t[[smileys/ohwell.png]]"
+msgstr "\\\\:\\\t[[smileys/ohwell.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-\\\t[[smileys/ohwell.png]]"
+msgstr "\\\\:-\\\t[[smileys/ohwell.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:/\t[[smileys/ohwell.png]]"
+msgstr "\\\\:/\t[[smileys/ohwell.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-/\t[[smileys/ohwell.png]]"
+msgstr "\\\\:-/\t[[smileys/ohwell.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:|\t[[smileys/neutral.png]]"
+msgstr "\\\\:|\t[[smileys/neutral.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-|\t[[smileys/neutral.png]]"
+msgstr "\\\\:-|\t[[smileys/neutral.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\>:>\t[[smileys/devil.png]]"
+msgstr "\\\\>:>\t[[smileys/devil.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\X-(\t[[smileys/angry.png]]"
+msgstr "\\\\X-(\t[[smileys/angry.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\<:(\t[[smileys/frown.png]]"
+msgstr "\\\\<:(\t[[smileys/frown.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:(\t[[smileys/sad.png]]"
+msgstr "\\\\:(\t[[smileys/sad.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-(\t[[smileys/sad.png]]"
+msgstr "\\\\:-(\t[[smileys/sad.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-?\t[[smileys/tongue.png]]"
+msgstr "\\\\:-?\t[[smileys/tongue.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:-P\t[[smileys/tongue.png]]"
+msgstr "\\\\:-P\t[[smileys/tongue.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\:o\t[[smileys/redface.png]]"
+msgstr "\\\\:o\t[[smileys/redface.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\|)\t[[smileys/tired.png]]"
+msgstr "\\\\|)\t[[smileys/tired.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\|-)\t[[smileys/tired.png]]"
+msgstr "\\\\|-)\t[[smileys/tired.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{OK}\t[[smileys/thumbs-up.png]]"
+msgstr "\\\\{OK}\t[[smileys/thumbs-up.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{X}\t[[smileys/icon-error.png]]"
+msgstr "\\\\{X}\t[[smileys/icon-error.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{i}\t[[smileys/icon-info.png]]"
+msgstr "\\\\{i}\t[[smileys/icon-info.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\(./)\t[[smileys/checkmark.png]]"
+msgstr "\\\\(./)\t[[smileys/checkmark.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\(!)\t[[smileys/idea.png]]"
+msgstr "\\\\(!)\t[[smileys/idea.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\[!]\t[[smileys/attention.png]]"
+msgstr "\\\\[!]\t[[smileys/attention.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\/!\\\t[[smileys/alert.png]]"
+msgstr "\\\\/!\\\t[[smileys/alert.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\(?)\t[[smileys/question.png]]"
+msgstr "\\\\(?)\t[[smileys/question.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{x}\t[[smileys/star_on.png]]"
+msgstr "\\\\{x}\t[[smileys/star_on.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{*}\t[[smileys/star_on.png]]"
+msgstr "\\\\{*}\t[[smileys/star_on.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{o}\t[[smileys/star_off.png]]"
+msgstr "\\\\{o}\t[[smileys/star_off.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{1}\t[[smileys/prio1.png]]"
+msgstr "\\\\{1}\t[[smileys/prio1.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{2}\t[[smileys/prio2.png]]"
+msgstr "\\\\{2}\t[[smileys/prio2.png]]"
+
+#. type: Bullet: '* '
+msgid "\\\\{3}\t[[smileys/prio3.png]]"
+msgstr "\\\\{3}\t[[smileys/prio3.png]]"
+
+#. type: Plain text
+msgid "For example: {x} B) {x}"
+msgstr "Eksempel: {x} B) {x}"
+
+#. type: Plain text
+msgid ""
+"To change the supported smileys, just edit the lists on this page. Note "
+"that the format is important; each list item should start with the text that "
+"is turned into the smiley, escaped so that users can see what produces it, "
+"followed by a [[ikiwiki/WikiLink]] to the image to display."
+msgstr ""
+"Redigér listen på denne side for at ændre understøttede smileys. Bemærk at "
+"formatet er vigtigt: hvert listeemne skal begynde med teksten der skal "
+"omdannes til en smiley, omskrevet så brugere kan se hvordan det dannes, "
+"efterfulgt af en [[ikiwiki/WikiLink]] til billedet der skal vises."
+
+#. type: Plain text
+msgid ""
+"/!\\ Bear in mind that the link to the image needs to be written in a way "
+"that will work if it's copied to other pages on the wiki. So be sure to "
+"include the smileys directory in the path to the file."
+msgstr ""
+"/!\\ Tænk på at det er nødvendigt at skrive henvisningen til billedet på en "
+"måde så det virker hvis det kopieres til andre sider på wikien. Sørg derfor "
+"for at medtage smileys direkte i stien til filen."
msgstr ""
"Project-Id-Version: ikiwiki\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-03 14:52-0500\n"
+"POT-Creation-Date: 2009-08-15 14:07-0400\n"
"PO-Revision-Date: 2007-01-13 15:31+1030\n"
"Last-Translator: Clytie Siddall <clytie@riverland.net.au>\n"
"Language-Team: Vietnamese <vi-VN@googlegroups.com>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: LocFactoryEditor 1.6fc1\n"
-#: ../IkiWiki/CGI.pm:125
+#: ../IkiWiki/CGI.pm:113
msgid "You need to log in first."
msgstr "Trước tiên bạn cần phải đăng nhập."
-#: ../IkiWiki/CGI.pm:155
+#: ../IkiWiki/CGI.pm:146
+msgid ""
+"probable misconfiguration: sslcookie is set, but you are attempting to login "
+"via http, not https"
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:149
msgid "login failed, perhaps you need to turn on cookies?"
msgstr ""
-#: ../IkiWiki/CGI.pm:184
+#: ../IkiWiki/CGI.pm:168 ../IkiWiki/CGI.pm:299
+msgid "Your login session has expired."
+msgstr ""
+
+#: ../IkiWiki/CGI.pm:189
msgid "Login"
msgstr ""
-#: ../IkiWiki/CGI.pm:185
+#: ../IkiWiki/CGI.pm:190
#, fuzzy
msgid "Preferences"
msgstr "Tùy thích đã được lưu."
-#: ../IkiWiki/CGI.pm:186
+#: ../IkiWiki/CGI.pm:191
msgid "Admin"
msgstr ""
-#: ../IkiWiki/CGI.pm:235
+#: ../IkiWiki/CGI.pm:231
msgid "Preferences saved."
msgstr "Tùy thích đã được lưu."
-#: ../IkiWiki/CGI.pm:291
-#, perl-format
-msgid "%s is not an editable page"
-msgstr ""
-
-#: ../IkiWiki/CGI.pm:382 ../IkiWiki/Plugin/brokenlinks.pm:24
-#: ../IkiWiki/Plugin/inline.pm:241 ../IkiWiki/Plugin/opendiscussion.pm:17
-#: ../IkiWiki/Plugin/orphans.pm:28 ../IkiWiki/Render.pm:95
-#: ../IkiWiki/Render.pm:175
-msgid "discussion"
-msgstr "thảo luận"
+#: ../IkiWiki/CGI.pm:262
+msgid "You are banned."
+msgstr "Bạn bị cấm ra."
-#: ../IkiWiki/CGI.pm:429
-#, perl-format
-msgid "creating %s"
-msgstr "đang tạo %s"
+#: ../IkiWiki/CGI.pm:390 ../IkiWiki/CGI.pm:391 ../IkiWiki.pm:1260
+msgid "Error"
+msgstr "Lỗi"
-#: ../IkiWiki/CGI.pm:447 ../IkiWiki/CGI.pm:466 ../IkiWiki/CGI.pm:476
-#: ../IkiWiki/CGI.pm:510 ../IkiWiki/CGI.pm:554
-#, perl-format
-msgid "editing %s"
-msgstr "đang sửa %s"
+#: ../IkiWiki/Plugin/aggregate.pm:84
+msgid "Aggregation triggered via web."
+msgstr ""
-#: ../IkiWiki/CGI.pm:643
-msgid "You are banned."
-msgstr "Bạn bị cấm ra."
+#: ../IkiWiki/Plugin/aggregate.pm:93
+msgid "Nothing to do right now, all feeds are up-to-date!"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:72
+#: ../IkiWiki/Plugin/aggregate.pm:220
#, fuzzy, perl-format
msgid "missing %s parameter"
msgstr "mẫu thiếu tham số id"
-#: ../IkiWiki/Plugin/aggregate.pm:100
+#: ../IkiWiki/Plugin/aggregate.pm:255
msgid "new feed"
msgstr "nguồn tin mới"
-#: ../IkiWiki/Plugin/aggregate.pm:114
+#: ../IkiWiki/Plugin/aggregate.pm:269
msgid "posts"
msgstr "bài"
-#: ../IkiWiki/Plugin/aggregate.pm:116
+#: ../IkiWiki/Plugin/aggregate.pm:271
msgid "new"
msgstr "mới"
-#: ../IkiWiki/Plugin/aggregate.pm:232
+#: ../IkiWiki/Plugin/aggregate.pm:441
#, perl-format
msgid "expiring %s (%s days old)"
msgstr "đang mãn hạn %s (cũ %s ngày)"
-#: ../IkiWiki/Plugin/aggregate.pm:239
+#: ../IkiWiki/Plugin/aggregate.pm:448
#, perl-format
msgid "expiring %s"
msgstr "đang mãn hạn %s"
-#: ../IkiWiki/Plugin/aggregate.pm:265
+#: ../IkiWiki/Plugin/aggregate.pm:475
#, perl-format
-msgid "processed ok at %s"
-msgstr "đã xử lý được ở %s"
+msgid "last checked %s"
+msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:270
+#: ../IkiWiki/Plugin/aggregate.pm:479
#, perl-format
msgid "checking feed %s ..."
msgstr "đang kiểm tra nguồn tin %s ..."
-#: ../IkiWiki/Plugin/aggregate.pm:275
+#: ../IkiWiki/Plugin/aggregate.pm:484
#, perl-format
msgid "could not find feed at %s"
msgstr "không tìm thấy nguồn tin ở %s"
-#: ../IkiWiki/Plugin/aggregate.pm:290
+#: ../IkiWiki/Plugin/aggregate.pm:503
#, fuzzy
msgid "feed not found"
msgstr "không tìm thấy mẫu %s"
-#: ../IkiWiki/Plugin/aggregate.pm:301
+#: ../IkiWiki/Plugin/aggregate.pm:514
#, perl-format
msgid "(invalid UTF-8 stripped from feed)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:307
+#: ../IkiWiki/Plugin/aggregate.pm:522
#, perl-format
msgid "(feed entities escaped)"
msgstr ""
-#: ../IkiWiki/Plugin/aggregate.pm:313
+#: ../IkiWiki/Plugin/aggregate.pm:530
msgid "feed crashed XML::Feed!"
msgstr "nguồn tin đã gây ra XML::Feed sụp đổ."
-#: ../IkiWiki/Plugin/aggregate.pm:387
+#: ../IkiWiki/Plugin/aggregate.pm:616
#, perl-format
msgid "creating new page %s"
msgstr "đang tạo trang mới %s"
-#: ../IkiWiki/Plugin/brokenlinks.pm:40
+#: ../IkiWiki/Plugin/amazon_s3.pm:31
+msgid "deleting bucket.."
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:38 ../ikiwiki.in:210
+msgid "done"
+msgstr "xong"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:97
+#, perl-format
+msgid "Must specify %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:136
+#, fuzzy
+msgid "Failed to create S3 bucket: "
+msgstr "Lỗi gửi thư"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:221
+#, fuzzy
+msgid "Failed to save file to S3: "
+msgstr "Lỗi gửi thư"
+
+#: ../IkiWiki/Plugin/amazon_s3.pm:243
+#, fuzzy
+msgid "Failed to delete file from S3: "
+msgstr "lỗi ghi %s: %s"
+
+#: ../IkiWiki/Plugin/attachment.pm:49
+#, perl-format
+msgid "there is already a page named %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:65
+msgid "prohibited by allowed_attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:140
+msgid "bad attachment filename"
+msgstr ""
+
+#: ../IkiWiki/Plugin/attachment.pm:182
+msgid "attachment upload"
+msgstr ""
+
+#: ../IkiWiki/Plugin/autoindex.pm:105
+msgid "automatic index generation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/blogspam.pm:108
+msgid ""
+"Sorry, but that looks like spam to <a href=\"http://blogspam.net/"
+"\">blogspam</a>: "
+msgstr ""
+
+#: ../IkiWiki/Plugin/brokenlinks.pm:42
#, perl-format
msgid "%s from %s"
msgstr ""
-#: ../IkiWiki/Plugin/brokenlinks.pm:47
+#: ../IkiWiki/Plugin/brokenlinks.pm:50
msgid "There are no broken links!"
msgstr "Không có liên kết bị ngắt nào."
-#: ../IkiWiki/Plugin/conditional.pm:18
+#: ../IkiWiki/Plugin/comments.pm:124 ../IkiWiki/Plugin/format.pm:38
+#, perl-format
+msgid "unsupported page format %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:129
+msgid "comment must have content"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:185
+msgid "Anonymous"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:340 ../IkiWiki/Plugin/editpage.pm:97
+msgid "bad page name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:345
+#, fuzzy, perl-format
+msgid "commenting on %s"
+msgstr "đang tạo %s"
+
+#: ../IkiWiki/Plugin/comments.pm:363
+#, perl-format
+msgid "page '%s' doesn't exist, so you can't comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:370
+#, perl-format
+msgid "comments on page '%s' are closed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:464
+msgid "comment stored for moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:466
+msgid "Your comment will be posted after moderator review"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:479
+msgid "Added a comment"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:483
+#, perl-format
+msgid "Added a comment: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:525 ../IkiWiki/Plugin/websetup.pm:236
+msgid "you are not logged in as an admin"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:576
+msgid "Comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:615
+msgid "comment moderation"
+msgstr ""
+
+#: ../IkiWiki/Plugin/comments.pm:766
+msgid "Comments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/conditional.pm:27 ../IkiWiki/Plugin/cutpaste.pm:30
+#: ../IkiWiki/Plugin/cutpaste.pm:45 ../IkiWiki/Plugin/cutpaste.pm:61
+#: ../IkiWiki/Plugin/testpagespec.pm:26
#, perl-format
msgid "%s parameter is required"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:41
+#: ../IkiWiki/Plugin/cutpaste.pm:66
+msgid "no text was copied in this page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/cutpaste.pm:69
+#, perl-format
+msgid "no text was copied in this page with id %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:40
+#, fuzzy, perl-format
+msgid "removing old preview %s"
+msgstr "đang gỡ bỏ trang cũ %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:113
+#, perl-format
+msgid "%s is not an editable page"
+msgstr ""
+
+#: ../IkiWiki/Plugin/editpage.pm:292
+#, perl-format
+msgid "creating %s"
+msgstr "đang tạo %s"
+
+#: ../IkiWiki/Plugin/editpage.pm:310 ../IkiWiki/Plugin/editpage.pm:329
+#: ../IkiWiki/Plugin/editpage.pm:339 ../IkiWiki/Plugin/editpage.pm:383
+#: ../IkiWiki/Plugin/editpage.pm:422
+#, perl-format
+msgid "editing %s"
+msgstr "đang sửa %s"
+
+#: ../IkiWiki/Plugin/edittemplate.pm:51
#, fuzzy
msgid "template not specified"
msgstr "không tìm thấy mẫu %s"
-#: ../IkiWiki/Plugin/edittemplate.pm:44
+#: ../IkiWiki/Plugin/edittemplate.pm:54
#, fuzzy
msgid "match not specified"
msgstr "chưa xác định tên tập tin bộ bao bọc"
-#: ../IkiWiki/Plugin/edittemplate.pm:49
+#: ../IkiWiki/Plugin/edittemplate.pm:62
#, perl-format
msgid "edittemplate %s registered for %s"
msgstr ""
-#: ../IkiWiki/Plugin/edittemplate.pm:111
+#: ../IkiWiki/Plugin/edittemplate.pm:133
#, fuzzy
msgid "failed to process"
msgstr "mẫu không xử lý được:"
-#: ../IkiWiki/Plugin/fortune.pm:18
+#: ../IkiWiki/Plugin/format.pm:20
+msgid "must specify format and text"
+msgstr ""
+
+#: ../IkiWiki/Plugin/fortune.pm:27
msgid "fortune failed"
msgstr "fortune bị lỗi"
-#: ../IkiWiki/Plugin/googlecalendar.pm:22
+#: ../IkiWiki/Plugin/getsource.pm:62 ../IkiWiki/Plugin/goto.pm:55
+#, fuzzy
+msgid "missing page"
+msgstr "mẫu thiếu tham số id"
+
+#: ../IkiWiki/Plugin/getsource.pm:64 ../IkiWiki/Plugin/goto.pm:57
+#, perl-format
+msgid "The page %s does not exist."
+msgstr ""
+
+#: ../IkiWiki/Plugin/getsource.pm:73
#, fuzzy
-msgid "failed to find url in html"
-msgstr "googlecalendar không tìm thấy địa chỉ URL trong mã HTML"
+msgid "not a page"
+msgstr "không thể đọc %s: %s"
+
+#: ../IkiWiki/Plugin/getsource.pm:75
+#, perl-format
+msgid "%s is an attachment, not a page."
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:626 ../IkiWiki/Plugin/git.pm:644
+#: ../IkiWiki/Receive.pm:129
+#, perl-format
+msgid "you are not allowed to change %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:666
+#, perl-format
+msgid "you cannot act on a file with mode %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/git.pm:670
+msgid "you are not allowed to change file modes"
+msgstr ""
-#: ../IkiWiki/Plugin/graphviz.pm:58
+#: ../IkiWiki/Plugin/google.pm:27 ../IkiWiki/Plugin/po.pm:129
+#: ../IkiWiki/Plugin/search.pm:36
+#, fuzzy, perl-format
+msgid "Must specify %s when using the %s plugin"
+msgstr "Cần phải xác định %s khi dùng bổ sung tìm kiếm"
+
+#: ../IkiWiki/Plugin/google.pm:31
+msgid "Failed to parse url, cannot determine domain name"
+msgstr ""
+
+#: ../IkiWiki/Plugin/graphviz.pm:67
#, fuzzy
msgid "failed to run graphviz"
msgstr "linkmap không chạy dot được"
-#: ../IkiWiki/Plugin/graphviz.pm:85
+#: ../IkiWiki/Plugin/graphviz.pm:94
msgid "prog not a valid graphviz program"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:53
+#: ../IkiWiki/Plugin/highlight.pm:47
+#, perl-format
+msgid "tohighlight contains unknown file type '%s'"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:58
+#, perl-format
+msgid "Source code: %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/highlight.pm:123
+msgid ""
+"warning: highlight perl module not available; falling back to pass through"
+msgstr ""
+
+#: ../IkiWiki/Plugin/img.pm:63
+#, fuzzy
+msgid "Image::Magick is not installed"
+msgstr "chưa cài đặt polygen"
+
+#: ../IkiWiki/Plugin/img.pm:72
#, perl-format
-msgid "bad size \"%s\""
+msgid "wrong size format \"%s\" (should be WxH)"
msgstr ""
-#: ../IkiWiki/Plugin/img.pm:63 ../IkiWiki/Plugin/img.pm:67
-#: ../IkiWiki/Plugin/img.pm:84
+#: ../IkiWiki/Plugin/img.pm:83 ../IkiWiki/Plugin/img.pm:87
+#: ../IkiWiki/Plugin/img.pm:104
#, fuzzy, perl-format
msgid "failed to read %s: %s"
msgstr "lỗi ghi %s: %s"
-#: ../IkiWiki/Plugin/img.pm:70
+#: ../IkiWiki/Plugin/img.pm:90
#, fuzzy, perl-format
msgid "failed to resize: %s"
msgstr "lỗi ghi %s: %s"
-#: ../IkiWiki/Plugin/img.pm:101
+#: ../IkiWiki/Plugin/img.pm:119
#, fuzzy, perl-format
msgid "failed to determine size of image %s"
msgstr "lỗi ghi %s: %s"
-#: ../IkiWiki/Plugin/inline.pm:42
+#: ../IkiWiki/Plugin/inline.pm:92
msgid "Must specify url to wiki with --url when using --rss or --atom"
msgstr ""
"Cần phải xác định địa chỉ URL tới wiki với « --url » khi dùng « --rss » hay « --"
"atom »"
-#: ../IkiWiki/Plugin/inline.pm:135
+#: ../IkiWiki/Plugin/inline.pm:138
+#, fuzzy
+msgid "page editing not allowed"
+msgstr "không tìm thấy mẫu %s"
+
+#: ../IkiWiki/Plugin/inline.pm:155
+#, fuzzy
+msgid "missing pages parameter"
+msgstr "mẫu thiếu tham số id"
+
+#: ../IkiWiki/Plugin/inline.pm:191
+#, perl-format
+msgid "the %s and %s parameters cannot be used together"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:212
+msgid "Sort::Naturally needed for title_natural sort"
+msgstr ""
+
+#: ../IkiWiki/Plugin/inline.pm:223
#, perl-format
msgid "unknown sort type %s"
msgstr "kiểu sắp xếp không rõ %s"
-#: ../IkiWiki/Plugin/inline.pm:200
+#: ../IkiWiki/Plugin/inline.pm:327
msgid "Add a new post titled:"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:216
+#: ../IkiWiki/Plugin/inline.pm:347
#, perl-format
msgid "nonexistant template %s"
msgstr ""
-#: ../IkiWiki/Plugin/inline.pm:249 ../IkiWiki/Render.pm:99
-msgid "Discussion"
-msgstr "Thảo luận"
-
-#: ../IkiWiki/Plugin/inline.pm:463
+#: ../IkiWiki/Plugin/inline.pm:612
msgid "RPC::XML::Client not found, not pinging"
msgstr "Không tìm thấy RPC::XML::Client nên không gửi gói tin ping"
-#: ../IkiWiki/Plugin/linkmap.pm:98
+#: ../IkiWiki/Plugin/linkmap.pm:106
#, fuzzy
msgid "failed to run dot"
msgstr "linkmap không chạy dot được"
-#: ../IkiWiki/Plugin/lockedit.pm:29
-#, perl-format
-msgid "%s is locked by %s and cannot be edited"
+#: ../IkiWiki/Plugin/lockedit.pm:47
+#, fuzzy, perl-format
+msgid "%s is locked and cannot be edited"
msgstr "%s bị %s khoá nên không thể sửa được"
-#: ../IkiWiki/Plugin/mdwn.pm:37
+#: ../IkiWiki/Plugin/mdwn.pm:44
+msgid "multimarkdown is enabled, but Text::MultiMarkdown is not installed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/mdwn.pm:67
#, perl-format
msgid "failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"
msgstr "lỗi nạp mô-đun perl Markdown.pm (%s) hay « /usr/bin/markdown » (%s)"
-#: ../IkiWiki/Plugin/meta.pm:119
+#: ../IkiWiki/Plugin/meta.pm:158
#, fuzzy
msgid "stylesheet not found"
msgstr "không tìm thấy mẫu %s"
-#: ../IkiWiki/Plugin/meta.pm:143
+#: ../IkiWiki/Plugin/meta.pm:196
#, fuzzy
msgid "redir page not found"
msgstr "không tìm thấy mẫu %s"
-#: ../IkiWiki/Plugin/meta.pm:156
+#: ../IkiWiki/Plugin/meta.pm:210
#, fuzzy
msgid "redir cycle is not allowed"
msgstr "không tìm thấy mẫu %s"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirrors"
msgstr "Nhân bản"
-#: ../IkiWiki/Plugin/mirrorlist.pm:23
+#: ../IkiWiki/Plugin/mirrorlist.pm:42
msgid "Mirror"
msgstr "Nhân bản"
msgid "more"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:45
+#: ../IkiWiki/Plugin/norcs.pm:65
+msgid "getctime not implemented"
+msgstr "chưa thực hiện getctime"
+
+#: ../IkiWiki/Plugin/openid.pm:61
msgid "Log in with"
msgstr ""
-#: ../IkiWiki/Plugin/openid.pm:48
+#: ../IkiWiki/Plugin/openid.pm:64
msgid "Get an OpenID"
msgstr "Lấy OpenID"
-#: ../IkiWiki/Plugin/orphans.pm:42
-msgid "All pages are linked to by other pages."
+#: ../IkiWiki/Plugin/orphans.pm:45
+#, fuzzy
+msgid "All pages have other pages linking to them."
msgstr "Mọi trang được liên kết với trang khác."
-#: ../IkiWiki/Plugin/pagetemplate.pm:21
+#: ../IkiWiki/Plugin/pagetemplate.pm:30
msgid "bad or missing template"
msgstr ""
-#: ../IkiWiki/Plugin/passwordauth.pm:162
+#: ../IkiWiki/Plugin/passwordauth.pm:248
msgid "Account creation successful. Now you can Login."
msgstr "Tài khoản đã được tạo. Lúc bây giờ bạn có thể đăng nhập."
-#: ../IkiWiki/Plugin/passwordauth.pm:165
+#: ../IkiWiki/Plugin/passwordauth.pm:251
msgid "Error creating account."
msgstr "Gặp lỗi khi tạo tài khoản."
-#: ../IkiWiki/Plugin/passwordauth.pm:186
+#: ../IkiWiki/Plugin/passwordauth.pm:258
+msgid "No email address, so cannot email password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:292
msgid "Failed to send mail"
msgstr "Lỗi gửi thư"
-#: ../IkiWiki/Plugin/passwordauth.pm:188
-msgid "Your password has been emailed to you."
-msgstr "Mật khẩu đã được gửi đính kèm thư cho bạn."
+#: ../IkiWiki/Plugin/passwordauth.pm:294
+msgid "You have been mailed password reset instructions."
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:329
+msgid "incorrect password reset url"
+msgstr ""
+
+#: ../IkiWiki/Plugin/passwordauth.pm:332
+msgid "password reset denied"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pingee.pm:30
+msgid "Ping received."
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:53
+msgid "requires 'from' and 'to' parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:58
+#, fuzzy, perl-format
+msgid "Will ping %s"
+msgstr "đang sửa %s"
+
+#: ../IkiWiki/Plugin/pinger.pm:61
+#, perl-format
+msgid "Ignoring ping directive for wiki %s (this wiki is %s)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/pinger.pm:77
+#, fuzzy
+msgid "LWP not found, not pinging"
+msgstr "Không tìm thấy RPC::XML::Client nên không gửi gói tin ping"
+
+#: ../IkiWiki/Plugin/po.pm:15
+msgid "warning: Old po4a detected! Recommend upgrade to 0.35."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:136
+#, perl-format
+msgid "%s is not a valid language code"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:148
+#, perl-format
+msgid ""
+"%s is not a valid value for po_link_to, falling back to po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:153
+msgid ""
+"po_link_to=negotiated requires usedirs to be enabled, falling back to "
+"po_link_to=default"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:383
+#, perl-format
+msgid "rebuilding all pages to fix meta titles"
+msgstr ""
-#: ../IkiWiki/Plugin/poll.pm:64
+#: ../IkiWiki/Plugin/po.pm:387 ../IkiWiki/Render.pm:426
+#, fuzzy, perl-format
+msgid "building %s"
+msgstr "đang sửa %s"
+
+#: ../IkiWiki/Plugin/po.pm:424
+msgid "updated PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:448
+msgid ""
+"Can not remove a translation. If the master page is removed, however, its "
+"translations will be removed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:468
+msgid ""
+"Can not rename a translation. If the master page is renamed, however, its "
+"translations will be renamed as well."
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:829
+#, perl-format
+msgid "POT file (%s) does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:843
+#, fuzzy, perl-format
+msgid "failed to copy underlay PO file to %s"
+msgstr "lỗi biên dịch %s"
+
+#: ../IkiWiki/Plugin/po.pm:852
+#, fuzzy, perl-format
+msgid "failed to update %s"
+msgstr "lỗi biên dịch %s"
+
+#: ../IkiWiki/Plugin/po.pm:858
+#, fuzzy, perl-format
+msgid "failed to copy the POT file to %s"
+msgstr "lỗi biên dịch %s"
+
+#: ../IkiWiki/Plugin/po.pm:894
+msgid "N/A"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:907
+#, fuzzy, perl-format
+msgid "failed to translate %s"
+msgstr "lỗi ghi %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:983
+msgid "removed obsolete PO files"
+msgstr ""
+
+#: ../IkiWiki/Plugin/po.pm:1046 ../IkiWiki/Plugin/po.pm:1060
+#: ../IkiWiki/Plugin/po.pm:1100
+#, fuzzy, perl-format
+msgid "failed to write %s"
+msgstr "lỗi ghi %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1058
+#, fuzzy
+msgid "failed to translate"
+msgstr "linkmap không chạy dot được"
+
+#: ../IkiWiki/Plugin/po.pm:1063
+#, fuzzy, perl-format
+msgid "failed to read %s"
+msgstr "lỗi ghi %s: %s"
+
+#: ../IkiWiki/Plugin/po.pm:1112
+msgid "invalid gettext data, go back to previous page to continue edit"
+msgstr ""
+
+#: ../IkiWiki/Plugin/poll.pm:69
msgid "vote"
msgstr "bỏ phiếu"
-#: ../IkiWiki/Plugin/poll.pm:72
+#: ../IkiWiki/Plugin/poll.pm:77
msgid "Total votes:"
msgstr "Tổng số phiếu :"
-#: ../IkiWiki/Plugin/polygen.pm:32
+#: ../IkiWiki/Plugin/polygen.pm:41
msgid "polygen not installed"
msgstr "chưa cài đặt polygen"
-#: ../IkiWiki/Plugin/polygen.pm:51
-msgid "polygen failed"
-msgstr "lỗi polygen"
+#: ../IkiWiki/Plugin/polygen.pm:60
+#, fuzzy
+msgid "command failed"
+msgstr "fortune bị lỗi"
-#: ../IkiWiki/Plugin/postsparkline.pm:32
+#: ../IkiWiki/Plugin/postsparkline.pm:41
msgid "missing formula"
msgstr ""
-#: ../IkiWiki/Plugin/postsparkline.pm:39
+#: ../IkiWiki/Plugin/postsparkline.pm:48
msgid "unknown formula"
msgstr ""
msgid "%A night"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:78
+#: ../IkiWiki/Plugin/prettydate.pm:101
msgid "at teatime on %A"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:82
+#: ../IkiWiki/Plugin/prettydate.pm:105
msgid "at midnight"
msgstr ""
-#: ../IkiWiki/Plugin/prettydate.pm:85
+#: ../IkiWiki/Plugin/prettydate.pm:108
msgid "at noon on %A"
msgstr ""
-#: ../IkiWiki/Plugin/recentchanges.pm:74
+#: ../IkiWiki/Plugin/progress.pm:34
+#, perl-format
+msgid "illegal percent value %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/progress.pm:59
+msgid "need either `percent` or `totalpages` and `donepages` parameters"
+msgstr ""
+
+#: ../IkiWiki/Plugin/recentchangesdiff.pm:37
+msgid "(Diff truncated)"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:31 ../IkiWiki/Plugin/rename.pm:36
+#, perl-format
+msgid "%s does not exist"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:38
+#, fuzzy, perl-format
+msgid "%s is not in the srcdir, so it cannot be deleted"
+msgstr "%s bị %s khoá nên không thể sửa được"
+
+#: ../IkiWiki/Plugin/remove.pm:41 ../IkiWiki/Plugin/rename.pm:45
+#, perl-format
+msgid "%s is not a file"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:134
+#, perl-format
+msgid "confirm removal of %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:171
+msgid "Please select the attachments to remove."
+msgstr ""
+
+#: ../IkiWiki/Plugin/remove.pm:211
+msgid "removed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:42
+#, perl-format
+msgid "%s is not in the srcdir, so it cannot be renamed"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:62
#, fuzzy
-msgid "missing page"
-msgstr "mẫu thiếu tham số id"
+msgid "no change to the file name was specified"
+msgstr "chưa xác định tên tập tin bộ bao bọc"
-#: ../IkiWiki/Plugin/recentchanges.pm:76
+#: ../IkiWiki/Plugin/rename.pm:68
#, perl-format
-msgid "The page %s does not exist."
+msgid "illegal name"
msgstr ""
-#: ../IkiWiki/Plugin/search.pm:34
+#: ../IkiWiki/Plugin/rename.pm:73
#, perl-format
-msgid "Must specify %s when using the search plugin"
-msgstr "Cần phải xác định %s khi dùng bổ sung tìm kiếm"
+msgid "%s already exists"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:58
-msgid "cleaning hyperestraier search index"
-msgstr "đang làm sạch chỉ mục tìm kiếm hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:79
+#, perl-format
+msgid "%s already exists on disk"
+msgstr ""
-#: ../IkiWiki/Plugin/search.pm:64
-msgid "updating hyperestraier search index"
-msgstr "đang cập nhật chỉ mục tìm kiếm hyperestraier"
+#: ../IkiWiki/Plugin/rename.pm:122
+#, fuzzy, perl-format
+msgid "rename %s"
+msgstr "đang vẽ %s"
+
+#: ../IkiWiki/Plugin/rename.pm:161
+msgid "Also rename SubPages and attachments"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:247
+msgid "Only one attachment can be renamed at a time."
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:250
+msgid "Please select the attachment to rename."
+msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:18
-msgid "shortcut plugin will not work without a shortcuts.mdwn"
+#: ../IkiWiki/Plugin/rename.pm:347
+#, perl-format
+msgid "rename %s to %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/rename.pm:571
+#, fuzzy, perl-format
+msgid "update for rename of %s to %s"
+msgstr "cập nhật %2$s của %1$s bởi %3$s"
+
+#: ../IkiWiki/Plugin/search.pm:182
+#, perl-format
+msgid "need Digest::SHA1 to index %s"
msgstr ""
-#: ../IkiWiki/Plugin/shortcut.pm:27
+#: ../IkiWiki/Plugin/search.pm:217
+msgid "search"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:31
+#, perl-format
+msgid "shortcut plugin will not work without %s"
+msgstr ""
+
+#: ../IkiWiki/Plugin/shortcut.pm:44
#, fuzzy
msgid "missing name or url parameter"
msgstr "lối tắt thiếu tên hay tham số url"
#. translators: This is used to display what shortcuts are defined.
#. translators: First parameter is the name of the shortcut, the second
#. translators: is an URL.
-#: ../IkiWiki/Plugin/shortcut.pm:36
+#: ../IkiWiki/Plugin/shortcut.pm:54
#, fuzzy, perl-format
msgid "shortcut %s points to <i>%s</i>"
msgstr "lối tắt %s chỉ tới %s"
-#: ../IkiWiki/Plugin/smiley.pm:23
+#: ../IkiWiki/Plugin/smiley.pm:43
#, fuzzy
msgid "failed to parse any smileys"
msgstr "lỗi phân tách hình cười nào nên tắt bổ sung"
-#: ../IkiWiki/Plugin/sparkline.pm:63
+#: ../IkiWiki/Plugin/sparkline.pm:72
#, fuzzy
msgid "parse error"
msgstr "linkmap không chạy dot được"
-#: ../IkiWiki/Plugin/sparkline.pm:69
-msgid "bad featurepoint diameter"
+#: ../IkiWiki/Plugin/sparkline.pm:78
+msgid "invalid featurepoint diameter"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:79
-msgid "bad featurepoint location"
+#: ../IkiWiki/Plugin/sparkline.pm:88
+msgid "invalid featurepoint location"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:90
+#: ../IkiWiki/Plugin/sparkline.pm:99
msgid "missing values"
msgstr ""
-#: ../IkiWiki/Plugin/sparkline.pm:95
+#: ../IkiWiki/Plugin/sparkline.pm:104
#, fuzzy
-msgid "bad height value"
+msgid "invalid height value"
msgstr "linkmap không chạy dot được"
-#: ../IkiWiki/Plugin/sparkline.pm:102
+#: ../IkiWiki/Plugin/sparkline.pm:111
#, fuzzy
msgid "missing width parameter"
msgstr "mẫu thiếu tham số id"
-#: ../IkiWiki/Plugin/sparkline.pm:106
+#: ../IkiWiki/Plugin/sparkline.pm:115
#, fuzzy
-msgid "bad width value"
+msgid "invalid width value"
msgstr "linkmap không chạy dot được"
-#: ../IkiWiki/Plugin/sparkline.pm:144
+#: ../IkiWiki/Plugin/sparkline.pm:153
#, fuzzy
msgid "failed to run php"
msgstr "linkmap không chạy dot được"
-#: ../IkiWiki/Plugin/table.pm:22
+#: ../IkiWiki/Plugin/table.pm:31
msgid "cannot find file"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:64
+#: ../IkiWiki/Plugin/table.pm:87
msgid "unknown data format"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:72
+#: ../IkiWiki/Plugin/table.pm:95
msgid "empty data"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:92
+#: ../IkiWiki/Plugin/table.pm:114
msgid "Direct data download"
msgstr ""
-#: ../IkiWiki/Plugin/table.pm:126
+#: ../IkiWiki/Plugin/table.pm:148
#, fuzzy, perl-format
msgid "parse fail at line %d: %s"
msgstr "lỗi ghi %s: %s"
-#: ../IkiWiki/Plugin/template.pm:19
+#: ../IkiWiki/Plugin/template.pm:29
#, fuzzy
msgid "missing id parameter"
msgstr "mẫu thiếu tham số id"
-#: ../IkiWiki/Plugin/template.pm:26
+#: ../IkiWiki/Plugin/template.pm:36
#, perl-format
msgid "template %s not found"
msgstr "không tìm thấy mẫu %s"
-#: ../IkiWiki/Plugin/template.pm:45
+#: ../IkiWiki/Plugin/template.pm:55
#, fuzzy
msgid "failed to process:"
msgstr "mẫu không xử lý được:"
-#: ../IkiWiki/Plugin/teximg.pm:30
+#: ../IkiWiki/Plugin/teximg.pm:70
msgid "missing tex code"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:37
+#: ../IkiWiki/Plugin/teximg.pm:77
msgid "code includes disallowed latex commands"
msgstr ""
-#: ../IkiWiki/Plugin/teximg.pm:96
+#: ../IkiWiki/Plugin/teximg.pm:128
#, fuzzy
msgid "failed to generate image from code"
msgstr "lỗi ghi %s: %s"
-#: ../IkiWiki/Plugin/toggle.pm:88
-msgid "(not toggleable in preview mode)"
+#: ../IkiWiki/Plugin/websetup.pm:89
+msgid "plugin"
msgstr ""
-#: ../IkiWiki/Rcs/Stub.pm:62
-msgid "getctime not implemented"
-msgstr "chưa thực hiện getctime"
+#: ../IkiWiki/Plugin/websetup.pm:108
+#, perl-format
+msgid "enable %s?"
+msgstr ""
-#: ../IkiWiki/Render.pm:273 ../IkiWiki/Render.pm:294
+#: ../IkiWiki/Plugin/websetup.pm:240
+msgid "setup file for this wiki is not known"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:256
+msgid "main"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:257
+msgid "plugins"
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:395
+msgid ""
+"The configuration changes shown below require a wiki rebuild to take effect."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:399
+msgid ""
+"For the configuration changes shown below to fully take effect, you may need "
+"to rebuild the wiki."
+msgstr ""
+
+#: ../IkiWiki/Plugin/websetup.pm:436
+#, perl-format
+msgid "Error: %s exited nonzero (%s). Discarding setup changes."
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:35
+#, perl-format
+msgid "cannot determine id of untrusted committer %s"
+msgstr ""
+
+#: ../IkiWiki/Receive.pm:85
+#, fuzzy, perl-format
+msgid "bad file name %s"
+msgstr "đang bỏ qua tên tập tin sai %s"
+
+#: ../IkiWiki/Render.pm:264
+#, perl-format
+msgid ""
+"symlink found in srcdir path (%s) -- set allow_symlinks_before_srcdir to "
+"allow this"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:287 ../IkiWiki/Render.pm:312
#, perl-format
msgid "skipping bad filename %s"
msgstr "đang bỏ qua tên tập tin sai %s"
-#: ../IkiWiki/Render.pm:343
+#: ../IkiWiki/Render.pm:294
+#, perl-format
+msgid "%s has multiple possible source pages"
+msgstr ""
+
+#: ../IkiWiki/Render.pm:380
#, perl-format
msgid "removing old page %s"
msgstr "đang gỡ bỏ trang cũ %s"
-#: ../IkiWiki/Render.pm:384
+#: ../IkiWiki/Render.pm:421
#, perl-format
msgid "scanning %s"
msgstr "đang quét %s"
-#: ../IkiWiki/Render.pm:389
-#, perl-format
-msgid "rendering %s"
-msgstr "đang vẽ %s"
-
-#: ../IkiWiki/Render.pm:410
-#, perl-format
-msgid "rendering %s, which links to %s"
+#: ../IkiWiki/Render.pm:447
+#, fuzzy, perl-format
+msgid "building %s, which links to %s"
msgstr "đang vẽ %s mà liên kết tới %s"
-#: ../IkiWiki/Render.pm:431
-#, perl-format
-msgid "rendering %s, which depends on %s"
+#: ../IkiWiki/Render.pm:468
+#, fuzzy, perl-format
+msgid "building %s, which depends on %s"
msgstr "đang vẽ %s mà phụ thuộc vào %s"
-#: ../IkiWiki/Render.pm:470
-#, perl-format
-msgid "rendering %s, to update its backlinks"
+#: ../IkiWiki/Render.pm:507
+#, fuzzy, perl-format
+msgid "building %s, to update its backlinks"
msgstr "đang vẽ %s để cập nhật các liên kết ngược của nó"
-#: ../IkiWiki/Render.pm:482
-#, perl-format
-msgid "removing %s, no longer rendered by %s"
+#: ../IkiWiki/Render.pm:519
+#, fuzzy, perl-format
+msgid "removing %s, no longer built by %s"
msgstr "đang gỡ bỏ %s, không còn được vẽ lại bởi %s"
-#: ../IkiWiki/Render.pm:508
-#, perl-format
-msgid "ikiwiki: cannot render %s"
+#: ../IkiWiki/Render.pm:543
+#, fuzzy, perl-format
+msgid "ikiwiki: cannot build %s"
msgstr "ikiwiki: không thể vẽ %s"
#. translators: The first parameter is a filename, and the second
#. translators: is a (probably not translated) error message.
-#: ../IkiWiki/Setup.pm:15
+#: ../IkiWiki/Setup.pm:19
#, perl-format
msgid "cannot read %s: %s"
msgstr "không thể đọc %s: %s"
-#: ../IkiWiki/Setup/Standard.pm:32
-msgid "generating wrappers.."
-msgstr "đang tạo ra các bộ bao bọc.."
+#: ../IkiWiki/Setup/Automator.pm:34
+msgid "you must enter a wikiname (that contains alphanumerics)"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:72
-msgid "rebuilding wiki.."
-msgstr "đang xây dựng lại wiki.."
+#: ../IkiWiki/Setup/Automator.pm:71
+#, perl-format
+msgid "unsupported revision control system %s"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:75
-msgid "refreshing wiki.."
-msgstr "đang làm tươi wiki.."
+#: ../IkiWiki/Setup/Automator.pm:97
+msgid "failed to set up the repository with ikiwiki-makerepo"
+msgstr ""
-#: ../IkiWiki/Setup/Standard.pm:84
-msgid "done"
-msgstr "xong"
+#: ../IkiWiki/Setup/Automator.pm:115
+#, perl-format
+msgid "** Disabling plugin %s, since it is failing with this message:"
+msgstr ""
#: ../IkiWiki/Wrapper.pm:16
#, perl-format
msgid "wrapper filename not specified"
msgstr "chưa xác định tên tập tin bộ bao bọc"
-#. translators: The first parameter is a filename, and the second is
-#. translators: a (probably not translated) error message.
-#: ../IkiWiki/Wrapper.pm:48
-#, perl-format
-msgid "failed to write %s: %s"
-msgstr "lỗi ghi %s: %s"
-
#. translators: The parameter is a C filename.
-#: ../IkiWiki/Wrapper.pm:99
+#: ../IkiWiki/Wrapper.pm:152
#, perl-format
msgid "failed to compile %s"
msgstr "lỗi biên dịch %s"
#. translators: The parameter is a filename.
-#: ../IkiWiki/Wrapper.pm:119
+#: ../IkiWiki/Wrapper.pm:172
#, perl-format
msgid "successfully generated %s"
msgstr "%s đã được tạo ra"
msgid "usage: ikiwiki [options] source dest"
msgstr "cách sử dụng: ikiwiki [tùy chọn] nguồn đích"
-#: ../ikiwiki.in:81
+#: ../ikiwiki.in:14
+msgid " ikiwiki --setup configfile"
+msgstr ""
+
+#: ../ikiwiki.in:91
msgid "usage: --set var=value"
msgstr ""
-#: ../IkiWiki.pm:127
+#: ../ikiwiki.in:140
+msgid "generating wrappers.."
+msgstr "đang tạo ra các bộ bao bọc.."
+
+#: ../ikiwiki.in:199
+msgid "rebuilding wiki.."
+msgstr "đang xây dựng lại wiki.."
+
+#: ../ikiwiki.in:202
+msgid "refreshing wiki.."
+msgstr "đang làm tươi wiki.."
+
+#: ../IkiWiki.pm:225
+msgid "Discussion"
+msgstr "Thảo luận"
+
+#: ../IkiWiki.pm:494
msgid "Must specify url to wiki with --url when using --cgi"
msgstr "Cần phải xác định địa chỉ URL tới wiki với « --url » khi dùng « --cgi »"
-#: ../IkiWiki.pm:196 ../IkiWiki.pm:197
-msgid "Error"
-msgstr "Lỗi"
+#: ../IkiWiki.pm:540
+msgid "cannot use multiple rcs plugins"
+msgstr ""
-#. translators: The first parameter is a
-#. translators: preprocessor directive name,
-#. translators: the second a page name, the
-#. translators: third a number.
-#: ../IkiWiki.pm:750
+#: ../IkiWiki.pm:569
#, perl-format
-msgid "%s preprocessing loop detected on %s at depth %i"
+msgid "failed to load external plugin needed for %s plugin: %s"
+msgstr ""
+
+#: ../IkiWiki.pm:1243
+#, fuzzy, perl-format
+msgid "preprocessing loop detected on %s at depth %i"
msgstr "vòng lặp tiền xử lý %s được phát hiện trên %s ở độ sâu %i"
+#: ../IkiWiki.pm:1783
+msgid "yes"
+msgstr ""
+
+#: ../IkiWiki.pm:1915
+#, fuzzy, perl-format
+msgid "cannot match pages: %s"
+msgstr "không thể đọc %s: %s"
+
+#: ../auto.setup:16
+msgid "What will the wiki be named?"
+msgstr ""
+
+#: ../auto.setup:16
+msgid "wiki"
+msgstr ""
+
+#: ../auto.setup:18
+msgid "What revision control system to use?"
+msgstr ""
+
+#: ../auto.setup:20
+msgid "Which user (wiki account or openid) will be admin?"
+msgstr ""
+
+#: ../auto.setup:23
+msgid "What is the domain name of the web server?"
+msgstr ""
+
+#~ msgid "discussion"
+#~ msgstr "thảo luận"
+
+#~ msgid "rendering %s"
+#~ msgstr "đang vẽ %s"
+
+#, fuzzy
+#~ msgid "Must specify %s when using the google search plugin"
+#~ msgstr "Cần phải xác định %s khi dùng bổ sung tìm kiếm"
+
+#, fuzzy
+#~ msgid "failed to find url in html"
+#~ msgstr "googlecalendar không tìm thấy địa chỉ URL trong mã HTML"
+
+#~ msgid "processed ok at %s"
+#~ msgstr "đã xử lý được ở %s"
+
+#~ msgid "Your password has been emailed to you."
+#~ msgstr "Mật khẩu đã được gửi đính kèm thư cho bạn."
+
+#~ msgid "polygen failed"
+#~ msgstr "lỗi polygen"
+
+#~ msgid "cleaning hyperestraier search index"
+#~ msgstr "đang làm sạch chỉ mục tìm kiếm hyperestraier"
+
+#~ msgid "updating hyperestraier search index"
+#~ msgstr "đang cập nhật chỉ mục tìm kiếm hyperestraier"
+
#, fuzzy
#~ msgid ""
#~ "REV is not set, not running from mtn post-commit hook, cannot send "
#~ msgstr ""
#~ "Chưa đặt REV, không chạy từ móc sau gài vào nên không thể gửi thông báo"
-#~ msgid "update of %s's %s by %s"
-#~ msgstr "cập nhật %2$s của %1$s bởi %3$s"
-
#, fuzzy
#~ msgid "%s not found"
#~ msgstr "không tìm thấy mẫu %s"
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 17;
+
+BEGIN { use_ok("IkiWiki::Plugin::404"); }
+
+sub cgi_page_from_404 {
+ return IkiWiki::Plugin::404::cgi_page_from_404(shift, shift, shift);
+}
+
+$IkiWiki::config{htmlext} = 'html';
+
+is(cgi_page_from_404('/', 'http://example.com', 1), 'index');
+is(cgi_page_from_404('/index.html', 'http://example.com', 0), 'index');
+is(cgi_page_from_404('/', 'http://example.com/', 1), 'index');
+is(cgi_page_from_404('/index.html', 'http://example.com/', 0), 'index');
+
+is(cgi_page_from_404('/~user/foo/bar', 'http://example.com/~user', 1),
+ 'foo/bar');
+is(cgi_page_from_404('/~user/foo/bar/index.html', 'http://example.com/~user', 1),
+ 'foo/bar');
+is(cgi_page_from_404('/~user/foo/bar/', 'http://example.com/~user', 1),
+ 'foo/bar');
+is(cgi_page_from_404('/~user/foo/bar.html', 'http://example.com/~user', 0),
+ 'foo/bar');
+
+is(cgi_page_from_404('/~user/foo/bar', 'http://example.com/~user/', 1),
+ 'foo/bar');
+is(cgi_page_from_404('/~user/foo/bar/index.html', 'http://example.com/~user/', 1),
+ 'foo/bar');
+is(cgi_page_from_404('/~user/foo/bar/', 'http://example.com/~user/', 1),
+ 'foo/bar');
+is(cgi_page_from_404('/~user/foo/bar.html', 'http://example.com/~user/', 0),
+ 'foo/bar');
+
+is(cgi_page_from_404('/~user/foo', 'https://example.com/~user', 1),
+ 'foo');
+is(cgi_page_from_404('/~user/foo/index.html', 'https://example.com/~user', 1),
+ 'foo');
+is(cgi_page_from_404('/~user/foo/', 'https://example.com/~user', 1),
+ 'foo');
+is(cgi_page_from_404('/~user/foo.html', 'https://example.com/~user', 0),
+ 'foo');
use strict;
use Test::More 'no_plan';
-ok(! system("mkdir t/tmp"));
-ok(! system("make -q ikiwiki.out"));
-ok(! system("make extra_install DESTDIR=`pwd`/t/tmp/install PREFIX=/usr >/dev/null"));
-ok(! system("LANG= perl -T -I. ./ikiwiki.out -plugin smiley -plugin brokenlinks -rebuild -underlaydir=t/tmp/install/usr/share/ikiwiki/basewiki -templatedir=templates t/basewiki_brokenlinks t/tmp/out"));
-ok(`grep 'no broken links' t/tmp/out/index.html`);
-ok(-e "t/tmp/out/style.css");
-ok(! system("rm -rf t/tmp t/basewiki_brokenlinks/.ikiwiki"));
+ok(! system("rm -rf t/tmp; mkdir t/tmp"));
+ok(! system("make -s ikiwiki.out"));
+ok(! system("make underlay_install DESTDIR=`pwd`/t/tmp/install PREFIX=/usr >/dev/null"));
+
+foreach my $plugin ("", "listdirectives") {
+ ok(! system("perl -I. ./ikiwiki.out -rebuild -plugin brokenlinks ".
+ # always enabled because pages link to it conditionally,
+ # which brokenlinks cannot handle properly
+ "-plugin smiley ".
+ ($plugin ? "-plugin $plugin " : "").
+ "-underlaydir=t/tmp/install/usr/share/ikiwiki/basewiki ".
+ "-set underlaydirbase=t/tmp/install/usr/share/ikiwiki ".
+ "-templatedir=templates t/basewiki_brokenlinks t/tmp/out"));
+ my $result=`grep 'no broken links' t/tmp/out/index.html`;
+ ok(length($result));
+ if (! length $result) {
+ print STDERR "\n\nbroken links found".($plugin ? " (with $plugin)" : "")."\n";
+ system("grep '<li>' t/tmp/out/index.html >&2");
+ print STDERR "\n\n";
+ }
+ ok(-e "t/tmp/out/style.css"); # linked to..
+ ok(! system("rm -rf t/tmp/out t/basewiki_brokenlinks/.ikiwiki"));
+}
+ok(! system("rm -rf t/tmp"));
-[[brokenlinks ]]
+[[!brokenlinks ]]
}
}
}
-use Test::More tests => 11;
+use Test::More tests => 16;
BEGIN { use_ok("IkiWiki"); }
%config=IkiWiki::defaultconfig();
$config{rcs} = "bzr";
$config{srcdir} = "$dir/repo";
+IkiWiki::loadplugins();
IkiWiki::checkconfig();
system "bzr init $config{srcdir}";
is($#changes, 0);
is($changes[0]{message}[0]{"line"}, "Added the first page");
-is($changes[0]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test1");
is($changes[0]{user}, "Joe User");
# Manual commit
my $test2 = readfile("t/test2.mdwn");
writefile('test2.mdwn', $config{srcdir}, $test2);
-system "bzr add $config{srcdir}/test2.mdwn";
-system "bzr commit --author \"$user\" -m \"$message\" $config{srcdir}";
+system "bzr add --quiet $config{srcdir}/test2.mdwn";
+system "bzr commit --quiet --author \"$user\" -m \"$message\" $config{srcdir}";
@changes = IkiWiki::rcs_recentchanges(3);
is($#changes, 1);
is($changes[0]{message}[0]{"line"}, $message);
is($changes[0]{user}, $username);
-is($changes[0]{pages}[0]{"page"}, "test2.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test2");
-is($changes[1]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[1]{pages}[0]{"page"}, "test1");
my $ctime = IkiWiki::rcs_getctime("test2.mdwn");
ok($ctime >= time() - 20);
+writefile('test3.mdwn', $config{srcdir}, $test1);
+IkiWiki::rcs_add("test3.mdwn");
+IkiWiki::rcs_rename("test3.mdwn", "test4.mdwn");
+IkiWiki::rcs_commit_staged("Added the 4th page", "moo", "Joe User");
+
+@changes = IkiWiki::rcs_recentchanges(4);
+
+is($#changes, 2);
+is($changes[0]{pages}[0]{"page"}, "test4");
+
+ok(mkdir($config{srcdir}."/newdir"));
+IkiWiki::rcs_rename("test4.mdwn", "newdir/test5.mdwn");
+IkiWiki::rcs_commit_staged("Added the 5th page", "moo", "Joe User");
+
+@changes = IkiWiki::rcs_recentchanges(4);
+
+is($#changes, 3);
+is($changes[0]{pages}[0]{"page"}, "newdir/test5");
+
+IkiWiki::rcs_remove("newdir/test5.mdwn");
+IkiWiki::rcs_commit_staged("Remove the 5th page", "moo", "Joe User");
+
system "rm -rf $dir";
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 8;
+
+BEGIN { use_ok("IkiWiki"); }
+
+$IkiWiki::config{usedirs} = 1;
+$IkiWiki::config{htmlext} = "HTML";
+is(IkiWiki::beautify_urlpath("foo/bar"), "./foo/bar");
+is(IkiWiki::beautify_urlpath("../badger"), "../badger");
+is(IkiWiki::beautify_urlpath("./bleh"), "./bleh");
+is(IkiWiki::beautify_urlpath("foo/index.HTML"), "./foo/");
+is(IkiWiki::beautify_urlpath("index.HTML"), "./");
+is(IkiWiki::beautify_urlpath("../index.HTML"), "../");
+$IkiWiki::config{usedirs} = 0;
+is(IkiWiki::beautify_urlpath("foo/index.HTML"), "./foo/index.HTML");
use strict;
my $dir;
-my $gitrepo;
BEGIN {
$dir="/tmp/ikiwiki-test-git.$$";
- $gitrepo="$dir/repo";
my $git=`which git`;
chomp $git;
- if (! -x $git || ! mkdir($dir) || ! mkdir($gitrepo)) {
+ if (! -x $git || ! mkdir($dir)) {
eval q{
- use Test::More skip_all => "git not available or could not make test dirs"
+ use Test::More skip_all => "git not available or could not make test dir"
}
}
}
-use Test::More tests => 11;
+use Test::More tests => 18;
BEGIN { use_ok("IkiWiki"); }
%config=IkiWiki::defaultconfig();
$config{rcs} = "git";
$config{srcdir} = "$dir/src";
+IkiWiki::loadplugins();
IkiWiki::checkconfig();
-system "cd $gitrepo && git init >/dev/null 2>&1";
-system "cd $gitrepo && echo dummy > dummy; git add . >/dev/null 2>&1";
-system "cd $gitrepo && git commit -m Initial >/dev/null 2>&1";
-system "git clone -l -s $gitrepo $config{srcdir} >/dev/null 2>&1";
+ok (mkdir($config{srcdir}));
+is (system("./ikiwiki-makerepo git $config{srcdir} $dir/repo"), 0);
my @changes;
@changes = IkiWiki::rcs_recentchanges(3);
is($#changes, 0); # counts for dummy commit during repo creation
-is($changes[0]{message}[0]{"line"}, "Initial");
-is($changes[0]{pages}[0]{"page"}, "dummy");
+# ikiwiki-makerepo's first commit is setting up the .gitignore
+is($changes[0]{message}[0]{"line"}, "initial commit");
+is($changes[0]{pages}[0]{"page"}, ".gitignore");
# Web commit
my $test1 = readfile("t/test1.mdwn");
is($#changes, 1);
is($changes[0]{message}[0]{"line"}, "Added the first page");
-is($changes[0]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test1");
# Manual commit
my $message = "Added the second page";
is($#changes, 2);
is($changes[0]{message}[0]{"line"}, $message);
-is($changes[0]{pages}[0]{"page"}, "test2.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test2");
-is($changes[1]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[1]{pages}[0]{"page"}, "test1");
+
+# Renaming
+
+writefile('test3.mdwn', $config{srcdir}, $test1);
+IkiWiki::rcs_add("test3.mdwn");
+IkiWiki::rcs_rename("test3.mdwn", "test4.mdwn");
+IkiWiki::rcs_commit_staged("Added the 4th page", "moo", "Joe User");
+
+@changes = IkiWiki::rcs_recentchanges(4);
+
+is($#changes, 3);
+is($changes[0]{pages}[0]{"page"}, "test4");
+
+ok(mkdir($config{srcdir}."/newdir"));
+IkiWiki::rcs_rename("test4.mdwn", "newdir/test5.mdwn");
+IkiWiki::rcs_commit_staged("Added the 5th page", "moo", "Joe User");
+
+@changes = IkiWiki::rcs_recentchanges(4);
+
+is($#changes, 3);
+is($changes[0]{pages}[0]{"page"}, "newdir/test5");
+
+IkiWiki::rcs_remove("newdir/test5.mdwn");
+IkiWiki::rcs_commit_staged("Remove the 5th page", "moo", "Joe User");
system "rm -rf $dir";
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";
}
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+BEGIN {
+ eval q{
+ use HTML::TreeBuilder;
+ };
+ if ($@) {
+ eval q{use Test::More skip_all => "HTML::TreeBuilder not available"};
+ }
+ else {
+ eval q{use Test::More tests => 7};
+ }
+ use_ok("IkiWiki::Plugin::htmlbalance");
+}
+
+is(IkiWiki::Plugin::htmlbalance::sanitize(content => "<br></br>"), "<br />");
+is(IkiWiki::Plugin::htmlbalance::sanitize(content => "<div><p b=\"c\">hello world</div>"), "<div><p b=\"c\">hello world</p></div>");
+is(IkiWiki::Plugin::htmlbalance::sanitize(content => "<a></a></a>"), "<a></a>");
+is(IkiWiki::Plugin::htmlbalance::sanitize(content => "<b>foo <a</b>"), "<b>foo </b>");
+is(IkiWiki::Plugin::htmlbalance::sanitize(content => "<b> foo <a</a></b>"), "<b> foo </b>");
+is(IkiWiki::Plugin::htmlbalance::sanitize(content => "a>"), "a>");
$links{"Foo"}=["bar.png"];
$links{"bar"}=["Foo", "new-page"];
$links{"bar.png"}=[];
-$depends{"Foo"}="";
-$depends{"bar"}="foo*";
-$depends{"bar.png"}="";
+$depends{"Foo"}={};
+$depends{"bar"}={"foo*" => 1};
+$depends{"bar.png"}={};
$pagestate{"bar"}{meta}{title}="a page about bar";
$pagestate{"bar"}{meta}{moo}="mooooo";
# only loaded plugins save state, so this should not be saved out
"bar.png" => [],
}, "%links loaded correctly");
is_deeply(\%depends, {
- Foo => "",
- bar => "foo*",
- "bar.png" => "",
+ Foo => {},
+ bar => {"foo*" => 1},
+ "bar.png" => {},
}, "%depends loaded correctly");
is_deeply(\%pagestate, {
bar => {
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 7;
+
+BEGIN { use_ok("IkiWiki"); }
+
+is(linkpage("foo bar"), "foo_bar");
+is(linkpage("foo bar baz"), "foo_bar_baz");
+is(linkpage("foo bar/baz"), "foo_bar/baz");
+is(linkpage("foo bar&baz"), "foo_bar__38__baz");
+is(linkpage("foo bar & baz"), "foo_bar___38___baz");
+is(linkpage("foo bar_baz"), "foo_bar_baz");
%config=IkiWiki::defaultconfig();
$config{rcs} = "mercurial";
$config{srcdir} = "$dir/repo";
+IkiWiki::loadplugins();
IkiWiki::checkconfig();
system "hg init $config{srcdir}";
is($#changes, 0);
is($changes[0]{message}[0]{"line"}, "Added the first page");
-is($changes[0]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test1");
is($changes[0]{user}, "Joe User");
# Manual commit
is($#changes, 1);
is($changes[0]{message}[0]{"line"}, $message);
is($changes[0]{user}, $username);
-is($changes[0]{pages}[0]{"page"}, "test2.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test2");
-is($changes[1]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[1]{pages}[0]{"page"}, "test1");
my $ctime = IkiWiki::rcs_getctime("test2.mdwn");
is($ctime, 0);
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+BEGIN {
+ eval q{
+ use Net::OpenID::VerifiedIdentity;
+ };
+ if ($@) {
+ eval q{use Test::More skip_all => "Net::OpenID::VerifiedIdentity not available"};
+ }
+ else {
+ eval q{use Test::More tests => 9};
+ }
+ use_ok("IkiWiki::Plugin::openid");
+}
+
+# Some typical examples:
+
+# This test, when run by Test::Harness using perl -w, exposes a warning in
+# Net::OpenID::VerifiedIdentity. Normally that warning is not displayed, as
+# that module does not use warnings. To avoid cluttering the test output,
+# disable the -w switch temporarily.
+$^W=0;
+is(IkiWiki::openiduser('http://josephturian.blogspot.com'), 'josephturian [blogspot.com]');
+$^W=1;
+
+is(IkiWiki::openiduser('http://yam655.livejournal.com/'), 'yam655 [livejournal.com]');
+is(IkiWiki::openiduser('http://id.mayfirst.org/jamie/'), 'jamie [id.mayfirst.org]');
+
+# and some less typical ones taken from the ikiwiki commit history
+
+is(IkiWiki::openiduser('http://thm.id.fedoraproject.org/'), 'thm [id.fedoraproject.org]');
+is(IkiWiki::openiduser('http://dtrt.org/'), 'dtrt.org');
+is(IkiWiki::openiduser('http://alcopop.org/me/openid/'), 'openid [alcopop.org/me]');
+is(IkiWiki::openiduser('http://id.launchpad.net/882/bielawski1'), 'bielawski1 [id.launchpad.net/882]');
+is(IkiWiki::openiduser('http://technorati.com/people/technorati/drajt'), 'drajt [technorati.com/people/technorati]');
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 5;
+use Test::More tests => 19;
BEGIN { use_ok("IkiWiki"); }
-# Used internally.
-$IkiWiki::hooks{htmlize}{mdwn}=1;
-
+# define mdwn as an extension
+$IkiWiki::hooks{htmlize}{mdwn}={};
+is(pagetype("foo.mdwn"), "mdwn");
is(pagename("foo.mdwn"), "foo");
+is(pagetype("foo/bar.mdwn"), "mdwn");
is(pagename("foo/bar.mdwn"), "foo/bar");
+
+# bare files get the full filename as page name, undef type
+is(pagetype("foo.png"), undef);
is(pagename("foo.png"), "foo.png");
+is(pagetype("foo/bar.png"), undef);
+is(pagename("foo/bar.png"), "foo/bar.png");
+is(pagetype("foo"), undef);
is(pagename("foo"), "foo");
+
+# keepextension preserves the extension in the page name
+$IkiWiki::hooks{htmlize}{txt}={keepextension => 1};
+is(pagename("foo.txt"), "foo.txt");
+is(pagetype("foo.txt"), "txt");
+is(pagename("foo/bar.txt"), "foo/bar.txt");
+is(pagetype("foo/bar.txt"), "txt");
+
+# noextension makes extensionless files be treated as first-class pages
+$IkiWiki::hooks{htmlize}{Makefile}={noextension =>1};
+is(pagetype("Makefile"), "Makefile");
+is(pagename("Makefile"), "Makefile");
+is(pagetype("foo/Makefile"), "Makefile");
+is(pagename("foo/Makefile"), "foo/Makefile");
BEGIN { use_ok("IkiWiki"); }
ok(pagespec_match("foo", "*"));
+ok(!pagespec_match("foo", ""));
+ok(pagespec_match("foo", "!bar"));
ok(pagespec_match("page", "?ag?"));
ok(! pagespec_match("page", "?a?g?"));
ok(pagespec_match("foo.png", "*.*"));
ok(! pagespec_match("foo", "foo and !foo"));
ok(! pagespec_match("foo.png", "* and !*.*"));
ok(pagespec_match("foo", "(bar or ((meep and foo) or (baz or foo) or beep))"));
+ok(pagespec_match("foo", "(
+ bar
+ or (
+ (meep and foo)
+ or
+ (baz or foo)
+ or beep
+ )
+)"), "multiline complex pagespec");
ok(! pagespec_match("a/foo", "foo", location => "a/b"), "nonrelative fail");
ok(! pagespec_match("foo", "./*", location => "a/b"), "relative fail");
ok(pagespec_match("a/foo", "./*", location => "a/b"), "relative");
ok(pagespec_match("foo", "./*", location => "a"), "relative toplevel");
ok(pagespec_match("foo/bar", "*", location => "baz"), "absolute");
ok(! pagespec_match("foo", "foo and bar"), "foo and bar");
+ok(pagespec_match("{f}oo", "{*}*"), "curly match");
+ok(! pagespec_match("foo", "{*}*"), "curly !match");
# The link and backlink stuff needs this.
$config{userdir}="";
$links{"done"}=[];
$links{"examples/softwaresite/bugs/fails_to_frobnicate"}=[qw{done}];
$links{"examples/softwaresite/bugs/done"}=[];
+$links{"ook"}=[qw{/blog/tags/foo}];
ok(pagespec_match("foo", "link(bar)"), "link");
ok(pagespec_match("foo", "link(ba?)"), "glob link");
ok(! pagespec_match("quux", "backlink(foo)"), "failed backlink");
ok(! pagespec_match("bar", ""), "empty pagespec should match nothing");
ok(! pagespec_match("bar", " "), "blank pagespec should match nothing");
+ok(pagespec_match("ook", "link(blog/tags/foo)"), "link internal absolute success");
+ok(pagespec_match("ook", "link(/blog/tags/foo)"), "link explicit absolute success");
$IkiWiki::pagectime{foo}=1154532692; # Wed Aug 2 11:26 EDT 2006
$IkiWiki::pagectime{bar}=1154532695; # after
my $ret=pagespec_match("foo", "(invalid");
ok(! $ret, "syntax error");
ok($ret =~ /syntax error/, "error message");
-
-# old style globlists
-ok(pagespec_match("foo", "foo bar"), "simple list");
-ok(pagespec_match("bar", "foo bar"), "simple list 2");
-ok(pagespec_match("foo", "f?? !foz"));
-ok(! pagespec_match("foo", "f?? !foo"));
-ok(! pagespec_match("foo", "* !foo"));
-ok(! pagespec_match("foo", "foo !foo"));
-ok(! pagespec_match("foo.png", "* !*.*"));
+++ /dev/null
-#!/usr/bin/perl
-use warnings;
-use strict;
-use Test::More tests => 25;
-
-BEGIN { use_ok("IkiWiki"); }
-
-sub same {
- my $a=shift;
- my $b=shift;
- my $match=shift;
-
- my $imatch=(pagespec_match($match, $a) ||
- pagespec_match($match, $b));
- my $cmatch=pagespec_match($match, IkiWiki::pagespec_merge($a, $b));
-
- return $imatch == $cmatch;
-}
-
-ok(same("foo", "bar", "foo"), "basic match 1");
-ok(same("foo", "bar", "bar"), "basic match 2");
-ok(same("foo", "bar", "foobar"), "basic failed match");
-ok(same("foo", "!bar", "foo"), "basic match with inversion");
-ok(same("foo", "!bar", "bar"), "basic failed match with inversion");
-ok(same("!foo", "bar", "foo"), "basic failed match with inversion 2");
-ok(same("!foo", "bar", "bar"), "basic match with inversion 2");
-ok(same("!foo", "!bar", "foo"), "double inversion failed match");
-ok(same("!foo", "!bar", "bar"), "double inversion failed match 2");
-ok(same("*", "!bar", "foo"), "glob+inversion match");
-ok(same("*", "!bar", "bar"), "matching glob and matching inversion");
-ok(same("* !foo", "!bar", "bar"), "matching glob and matching inversion");
-ok(same("* !foo", "!bar", "foo"), "matching glob with matching inversion and non-matching inversion");
-ok(same("* !foo", "!foo", "foo"), "matching glob with matching inversion and matching inversion");
-ok(same("b??", "!b??", "bar"), "matching glob and matching inverted glob");
-ok(same("f?? !f??", "!bar", "bar"), "matching glob and matching inverted glob");
-ok(same("b??", "!b?z", "bar"), "matching glob and non-matching inverted glob");
-ok(same("f?? !f?z", "!bar", "bar"), "matching glob and non-matching inverted glob");
-ok(same("!foo bar baz", "!bar", "bar"), "matching list and matching inversion");
-ok(pagespec_match("foo/Discussion",
- IkiWiki::pagespec_merge("* !*/Discussion", "*/Discussion")), "should match");
-ok(same("* !*/Discussion", "*/Discussion", "foo/Discussion"), "Discussion merge 1");
-ok(same("*/Discussion", "* !*/Discussion", "foo/Discussion"), "Discussion merge 2");
-ok(same("*/Discussion !*/bar", "*/bar !*/Discussion", "foo/Discussion"), "bidirectional merge 1");
-ok(same("*/Discussion !*/bar", "*/bar !*/Discussion", "foo/bar"), "bidirectional merge 2");
BEGIN { use_ok("IkiWiki"); }
-is(IkiWiki::pagetitle("foo_bar"), "foo bar");
-is(IkiWiki::pagetitle("foo_bar_baz"), "foo bar baz");
-is(IkiWiki::pagetitle("foo_bar__33__baz"), "foo bar!baz");
-is(IkiWiki::pagetitle("foo_bar__1234__baz"), "foo barӒbaz");
-is(IkiWiki::pagetitle("foo_bar___33___baz"), "foo bar ! baz");
-is(IkiWiki::pagetitle("foo_bar___95___baz"), "foo bar _ baz");
+is(pagetitle("foo_bar"), "foo bar");
+is(pagetitle("foo_bar_baz"), "foo bar baz");
+is(pagetitle("foo_bar__33__baz"), "foo bar!baz");
+is(pagetitle("foo_bar__1234__baz"), "foo barӒbaz");
+is(pagetitle("foo_bar___33___baz"), "foo bar ! baz");
+is(pagetitle("foo_bar___95___baz"), "foo bar _ baz");
+++ /dev/null
-#!/usr/bin/perl
-use warnings;
-use strict;
-use Test::More tests => 5;
-
-BEGIN { use_ok("IkiWiki"); }
-
-# Used internally.
-$IkiWiki::hooks{htmlize}{mdwn}=1;
-
-is(pagetype("foo.mdwn"), "mdwn");
-is(pagetype("foo/bar.mdwn"), "mdwn");
-is(pagename("foo.png"), undef);
-is(pagename("foo"), undef);
--- /dev/null
+#!/usr/bin/perl
+# -*- cperl-indent-level: 8; -*-
+# Testcases for the Ikiwiki parentlinks plugin.
+
+use warnings;
+use strict;
+use Test::More 'no_plan';
+
+my %expected;
+
+BEGIN { use_ok("IkiWiki"); }
+
+# Init
+%config=IkiWiki::defaultconfig();
+$config{srcdir}=$config{destdir}="/dev/null";
+$config{underlaydir}="underlays/basewiki";
+$config{templatedir}="t/parentlinks/templates";
+IkiWiki::loadplugins();
+IkiWiki::checkconfig();
+
+# Test data
+$expected{'parentlinks'} =
+ {
+ "" => [],
+ "ikiwiki" => [],
+ "ikiwiki/pagespec" =>
+ [ {depth => 0, height => 2, },
+ {depth => 1, height => 1, },
+ ],
+ "ikiwiki/pagespec/attachment" =>
+ [ {depth => 0, height => 3, depth_0 => 1, height_3 => 1},
+ {depth => 1, height => 2, },
+ {depth => 2, height => 1, },
+ ],
+ };
+
+# Test function
+sub test_loop($$) {
+ my $loop=shift;
+ my $expected=shift;
+ my $template;
+ my %params;
+
+ ok($template=template('parentlinks.tmpl'), "template created");
+ ok($params{template}=$template, "params populated");
+
+ while ((my $page, my $exp) = each %{$expected}) {
+ my @path=(split("/", $page));
+ my $pagedepth=@path;
+ my $msgprefix="$page $loop";
+
+ # manually run the plugin hook
+ $params{page}=$page;
+ $template->clear_params();
+ IkiWiki::Plugin::parentlinks::pagetemplate(%params);
+ my $res=$template->param($loop);
+
+ is(scalar(@$res), $pagedepth, "$msgprefix: path length");
+ # logic & arithmetic validation tests
+ for (my $i=0; $i<$pagedepth; $i++) {
+ my $r=$res->[$i];
+ is($r->{height}, $pagedepth - $r->{depth},
+ "$msgprefix\[$i\]: height = pagedepth - depth");
+ ok($r->{depth} ge 0, "$msgprefix\[$i\]: depth>=0");
+ ok($r->{height} ge 0, "$msgprefix\[$i\]: height>=0");
+ }
+ # comparison tests, iff the test-suite has been written
+ if (scalar(@$exp) eq $pagedepth) {
+ for (my $i=0; $i<$pagedepth; $i++) {
+ my $e=$exp->[$i];
+ my $r=$res->[$i];
+ map { is($r->{$_}, $e->{$_}, "$msgprefix\[$i\]: $_"); } keys %$e;
+ }
+ }
+ # else {
+ # diag("Testsuite is incomplete for ($page,$loop); cannot run comparison tests.");
+ # }
+ }
+}
+
+# Main
+test_loop('parentlinks', $expected{'parentlinks'});
--- /dev/null
+<!-- This template file only has to "use" the loops tested by parentlinks.t -->
+
+<TMPL_LOOP NAME="PARENTLINKS">
+</TMPL_LOOP>
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More 'no_plan';
+
+ok(! system("mkdir t/tmp"));
+ok(! system("make -s ikiwiki.out"));
+ok(! system("perl -I. ./ikiwiki.out -plugin inline -url=http://example.com -cgiurl=http://example.com/ikiwiki.cgi -rss -atom -underlaydir=underlays/basewiki -templatedir=templates t/tinyblog t/tmp/out"));
+# This guid should never, ever change, for any reason whatsoever!
+my $guid="http://example.com/post/";
+ok(length `grep '<guid>$guid</guid>' t/tmp/out/index.rss`);
+ok(length `grep '<id>$guid</id>' t/tmp/out/index.atom`);
+ok(! system("rm -rf t/tmp t/tinyblog/.ikiwiki"));
--- /dev/null
+#!/usr/bin/perl
+# -*- cperl-indent-level: 8; -*-
+use warnings;
+use strict;
+use File::Temp qw{tempdir};
+
+BEGIN {
+ unless (eval { require Locale::Po4a::Chooser }) {
+ eval q{
+ use Test::More skip_all => "Locale::Po4a::Chooser::new is not available"
+ }
+ }
+ unless (eval { require Locale::Po4a::Po }) {
+ eval q{
+ use Test::More skip_all => "Locale::Po4a::Po::new is not available"
+ }
+ }
+}
+
+use Test::More tests => 65;
+
+BEGIN { use_ok("IkiWiki"); }
+
+my $msgprefix;
+
+my $dir = tempdir("ikiwiki-test-po.XXXXXXXXXX",
+ DIR => File::Spec->tmpdir,
+ CLEANUP => 1);
+
+### Init
+%config=IkiWiki::defaultconfig();
+$config{srcdir} = "$dir/src";
+$config{destdir} = "$dir/dst";
+$config{discussion} = 0;
+$config{po_master_language} = { code => 'en',
+ name => 'English'
+ };
+$config{po_slave_languages} = {
+ es => 'Castellano',
+ fr => "Français"
+ };
+$config{po_translatable_pages}='index or test1 or test2 or translatable';
+$config{po_link_to}='negotiated';
+IkiWiki::loadplugins();
+IkiWiki::checkconfig();
+ok(IkiWiki::loadplugin('po'), "po plugin loaded");
+
+### seed %pagesources and %pagecase
+$pagesources{'index'}='index.mdwn';
+$pagesources{'index.fr'}='index.fr.po';
+$pagesources{'index.es'}='index.es.po';
+$pagesources{'test1'}='test1.mdwn';
+$pagesources{'test1.fr'}='test1.fr.po';
+$pagesources{'test2'}='test2.mdwn';
+$pagesources{'test2.es'}='test2.es.po';
+$pagesources{'test2.fr'}='test2.fr.po';
+$pagesources{'test3'}='test3.mdwn';
+$pagesources{'test3.es'}='test3.es.mdwn';
+$pagesources{'translatable'}='translatable.mdwn';
+$pagesources{'translatable.fr'}='translatable.fr.po';
+$pagesources{'translatable.es'}='translatable.es.po';
+$pagesources{'nontranslatable'}='nontranslatable.mdwn';
+foreach my $page (keys %pagesources) {
+ $IkiWiki::pagecase{lc $page}=$page;
+}
+
+### populate srcdir
+writefile('index.mdwn', $config{srcdir}, '[[translatable]] [[nontranslatable]]');
+writefile('test1.mdwn', $config{srcdir}, 'test1 content');
+writefile('test2.mdwn', $config{srcdir}, 'test2 content');
+writefile('test3.mdwn', $config{srcdir}, 'test3 content');
+writefile('translatable.mdwn', $config{srcdir}, '[[nontranslatable]]');
+writefile('nontranslatable.mdwn', $config{srcdir}, '[[/]] [[translatable]]');
+
+### istranslatable/istranslation
+# we run these tests twice because memoization attempts made them
+# succeed once every two tries...
+foreach (1, 2) {
+ok(IkiWiki::Plugin::po::istranslatable('index'), "index is translatable");
+ok(IkiWiki::Plugin::po::istranslatable('/index'), "/index is translatable");
+ok(! IkiWiki::Plugin::po::istranslatable('index.fr'), "index.fr is not translatable");
+ok(! IkiWiki::Plugin::po::istranslatable('index.es'), "index.es is not translatable");
+ok(! IkiWiki::Plugin::po::istranslatable('/index.fr'), "/index.fr is not translatable");
+ok(! IkiWiki::Plugin::po::istranslation('index'), "index is not a translation");
+ok(IkiWiki::Plugin::po::istranslation('index.fr'), "index.fr is a translation");
+ok(IkiWiki::Plugin::po::istranslation('index.es'), "index.es is a translation");
+ok(IkiWiki::Plugin::po::istranslation('/index.fr'), "/index.fr is a translation");
+ok(IkiWiki::Plugin::po::istranslatable('test2'), "test2 is translatable");
+ok(! IkiWiki::Plugin::po::istranslation('test2'), "test2 is not a translation");
+ok(! IkiWiki::Plugin::po::istranslatable('test3'), "test3 is not translatable");
+ok(! IkiWiki::Plugin::po::istranslation('test3'), "test3 is not a translation");
+}
+
+### links
+require IkiWiki::Render;
+
+sub refresh_n_scan(@) {
+ my @masterfiles_rel=@_;
+ foreach my $masterfile_rel (@masterfiles_rel) {
+ my $masterfile=srcfile($masterfile_rel);
+ IkiWiki::scan($masterfile_rel);
+ next unless IkiWiki::Plugin::po::istranslatable(pagename($masterfile_rel));
+ my @pofiles=IkiWiki::Plugin::po::pofiles($masterfile);
+ IkiWiki::Plugin::po::refreshpot($masterfile);
+ IkiWiki::Plugin::po::refreshpofiles($masterfile, @pofiles);
+ map IkiWiki::scan(IkiWiki::abs2rel($_, $config{srcdir})), @pofiles;
+ }
+}
+
+$config{po_link_to}='negotiated';
+$msgprefix="links (po_link_to=negotiated)";
+refresh_n_scan('index.mdwn', 'translatable.mdwn', 'nontranslatable.mdwn');
+is_deeply(\@{$links{'index'}}, ['translatable', 'nontranslatable'], "$msgprefix index");
+is_deeply(\@{$links{'index.es'}}, ['translatable.es', 'nontranslatable'], "$msgprefix index.es");
+is_deeply(\@{$links{'index.fr'}}, ['translatable.fr', 'nontranslatable'], "$msgprefix index.fr");
+is_deeply(\@{$links{'translatable'}}, ['nontranslatable'], "$msgprefix translatable");
+is_deeply(\@{$links{'translatable.es'}}, ['nontranslatable'], "$msgprefix translatable.es");
+is_deeply(\@{$links{'translatable.fr'}}, ['nontranslatable'], "$msgprefix translatable.fr");
+is_deeply(\@{$links{'nontranslatable'}}, ['/', 'translatable', 'translatable.fr', 'translatable.es'], "$msgprefix nontranslatable");
+
+$config{po_link_to}='current';
+$msgprefix="links (po_link_to=current)";
+refresh_n_scan('index.mdwn', 'translatable.mdwn', 'nontranslatable.mdwn');
+is_deeply(\@{$links{'index'}}, ['translatable', 'nontranslatable'], "$msgprefix index");
+is_deeply(\@{$links{'index.es'}}, [ map bestlink('index.es', $_), ('translatable.es', 'nontranslatable')], "$msgprefix index.es");
+is_deeply(\@{$links{'index.fr'}}, [ map bestlink('index.fr', $_), ('translatable.fr', 'nontranslatable')], "$msgprefix index.fr");
+is_deeply(\@{$links{'translatable'}}, [bestlink('translatable', 'nontranslatable')], "$msgprefix translatable");
+is_deeply(\@{$links{'translatable.es'}}, ['nontranslatable'], "$msgprefix translatable.es");
+is_deeply(\@{$links{'translatable.fr'}}, ['nontranslatable'], "$msgprefix translatable.fr");
+is_deeply(\@{$links{'nontranslatable'}}, ['/', 'translatable', 'translatable.fr', 'translatable.es'], "$msgprefix nontranslatable");
+
+### targetpage
+$config{usedirs}=0;
+$msgprefix="targetpage (usedirs=0)";
+is(targetpage('test1', 'html'), 'test1.en.html', "$msgprefix test1");
+is(targetpage('test1.fr', 'html'), 'test1.fr.html', "$msgprefix test1.fr");
+$config{usedirs}=1;
+$msgprefix="targetpage (usedirs=1)";
+is(targetpage('index', 'html'), 'index.en.html', "$msgprefix index");
+is(targetpage('index.fr', 'html'), 'index.fr.html', "$msgprefix index.fr");
+is(targetpage('test1', 'html'), 'test1/index.en.html', "$msgprefix test1");
+is(targetpage('test1.fr', 'html'), 'test1/index.fr.html', "$msgprefix test1.fr");
+is(targetpage('test3', 'html'), 'test3/index.html', "$msgprefix test3 (non-translatable page)");
+is(targetpage('test3.es', 'html'), 'test3.es/index.html', "$msgprefix test3.es (non-translatable page)");
+
+### urlto -> index
+$config{po_link_to}='current';
+$msgprefix="urlto (po_link_to=current)";
+is(urlto('', 'index'), './index.en.html', "$msgprefix index -> ''");
+is(urlto('', 'nontranslatable'), '../index.en.html', "$msgprefix nontranslatable -> ''");
+is(urlto('', 'translatable.fr'), '../index.fr.html', "$msgprefix translatable.fr -> ''");
+$config{po_link_to}='negotiated';
+$msgprefix="urlto (po_link_to=negotiated)";
+is(urlto('', 'index'), './', "$msgprefix index -> ''");
+is(urlto('', 'nontranslatable'), '../', "$msgprefix nontranslatable -> ''");
+is(urlto('', 'translatable.fr'), '../', "$msgprefix translatable.fr -> ''");
+
+### bestlink
+$config{po_link_to}='current';
+$msgprefix="bestlink (po_link_to=current)";
+is(bestlink('test1.fr', 'test2'), 'test2.fr', "$msgprefix test1.fr -> test2");
+is(bestlink('test1.fr', 'test2.es'), 'test2.es', "$msgprefix test1.fr -> test2.es");
+$config{po_link_to}='negotiated';
+$msgprefix="bestlink (po_link_to=negotiated)";
+is(bestlink('test1.fr', 'test2'), 'test2.fr', "$msgprefix test1.fr -> test2");
+is(bestlink('test1.fr', 'test2.es'), 'test2.es', "$msgprefix test1.fr -> test2.es");
+
+### beautify_urlpath
+$config{po_link_to}='default';
+$msgprefix="beautify_urlpath (po_link_to=default)";
+is(IkiWiki::beautify_urlpath('test1/index.en.html'), './test1/index.en.html', "$msgprefix test1/index.en.html");
+is(IkiWiki::beautify_urlpath('test1/index.fr.html'), './test1/index.fr.html', "$msgprefix test1/index.fr.html");
+$config{po_link_to}='negotiated';
+$msgprefix="beautify_urlpath (po_link_to=negotiated)";
+is(IkiWiki::beautify_urlpath('test1/index.html'), './test1/', "$msgprefix test1/index.html");
+is(IkiWiki::beautify_urlpath('test1/index.en.html'), './test1/', "$msgprefix test1/index.en.html");
+is(IkiWiki::beautify_urlpath('test1/index.fr.html'), './test1/', "$msgprefix test1/index.fr.html");
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 19;
+use Test::More tests => 21;
BEGIN { use_ok("IkiWiki"); }
"foo(a => $multiline, b => foo)");
is(IkiWiki::preprocess("foo", "foo", '[[foo a="""'."\n".$multiline."\n".'""" b="foo"]]', 0, 0),
"foo(a => $multiline, b => foo)", "leading/trailing newline stripped");
+my $long='[[foo a="""'.("a" x 100000).'';
+is(IkiWiki::preprocess("foo", "foo", $long, 0, 0), $long,
+ "unterminated triple-quoted string inside unterminated directive(should not warn about over-recursion)");
+is(IkiWiki::preprocess("foo", "foo", $long."]]", 0, 0), $long."]]",
+ "unterminated triple-quoted string is not treated as a bare word");
TODO: {
local $TODO = "nested strings not yet implemented";
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 21;
+use Encode;
+
+BEGIN { use_ok("IkiWiki"); }
+BEGIN { use_ok("IkiWiki::Plugin::link"); }
+
+%config=IkiWiki::defaultconfig();
+$config{srcdir}=$config{destdir}="/dev/null";
+IkiWiki::checkconfig();
+
+# tests of the link plugin's renamepage function
+sub try {
+ my ($page, $oldpage, $newpage, $content)=@_;
+
+ %IkiWiki::pagecase=();
+ %links=();
+ $IkiWiki::config{userdir}="foouserdir";
+ foreach my $page ($page, $oldpage, $newpage) {
+ $IkiWiki::pagecase{lc $page}=$page;
+ $links{$page}=[];
+ }
+
+ IkiWiki::Plugin::link::renamepage(
+ page => $page,
+ oldpage => $oldpage,
+ newpage => $newpage,
+ content => $content,
+ );
+}
+is(try("z", "foo" => "bar", "[[xxx]]"), "[[xxx]]"); # unrelated link
+is(try("z", "foo" => "bar", "[[bar]]"), "[[bar]]"); # link already to new page
+is(try("z", "foo" => "bar", "[[foo]]"), "[[bar]]"); # basic conversion to new page name
+is(try("z", "foo" => "bar", "[[/foo]]"), "[[/bar]]"); # absolute link
+is(try("z", "foo" => "bar", "[[Foo]]"), "[[Bar]]"); # preserve case
+is(try("z", "x/foo" => "x/bar", "[[x/Foo]]"), "[[x/Bar]]"); # preserve case of subpage
+is(try("z", "foo" => "bar", "[[/Foo]]"), "[[/Bar]]"); # preserve case w/absolute
+is(try("z", "foo" => "bar", "[[foo]] [[xxx]]"), "[[bar]] [[xxx]]"); # 2 links, 1 converted
+is(try("z", "foo" => "bar", "[[xxx|foo]]"), "[[xxx|bar]]"); # conversion w/text
+is(try("z", "foo" => "bar", "[[foo#anchor]]"), "[[bar#anchor]]"); # with anchor
+is(try("z", "foo" => "bar", "[[xxx|foo#anchor]]"), "[[xxx|bar#anchor]]"); # with anchor
+is(try("z", "foo" => "bar", "[[!moo ]]"), "[[!moo ]]"); # preprocessor directive unchanged
+is(try("bugs", "bugs/foo" => "wishlist/bar", "[[foo]]"), "[[wishlist/bar]]"); # subpage link
+is(try("z", "foo_bar" => "bar", "[[foo_bar]]"), "[[bar]]"); # old link with underscore
+is(try("z", "foo" => "bar_foo", "[[foo]]"), "[[bar_foo]]"); # new link with underscore
+is(try("z", "foo_bar" => "bar_foo", "[[foo_bar]]"), "[[bar_foo]]"); # both with underscore
+is(try("z", "foo" => "bar__".ord("(")."__", "[[foo]]"), "[[bar(]]"); # new link with escaped chars
+is(try("z", "foo__".ord("(")."__" => "bar(", "[[foo(]]"), "[[bar(]]"); # old link with escaped chars
+is(try("z", "foo__".ord("(")."__" => "bar__".ord(")")."__", "[[foo(]]"), "[[bar)]]"); # both with escaped chars
$config{srcdir} = "$dir/src";
$config{svnrepo} = "$dir/repo";
$config{svnpath} = "trunk";
+IkiWiki::loadplugins();
IkiWiki::checkconfig();
my $svnrepo = "$dir/repo";
is($#changes, 0);
is($changes[0]{message}[0]{"line"}, "Added the first page");
-is($changes[0]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test1");
# Manual commit
my $message = "Added the second page";
@changes = IkiWiki::rcs_recentchanges(3);
is($#changes, 1);
is($changes[0]{message}[0]{"line"}, $message);
-is($changes[0]{pages}[0]{"page"}, "test2.mdwn");
-is($changes[1]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test2");
+is($changes[1]{pages}[0]{"page"}, "test1");
# extra slashes in the path shouldn't break things
$config{svnpath} = "/trunk//";
@changes = IkiWiki::rcs_recentchanges(3);
is($#changes, 1);
is($changes[0]{message}[0]{"line"}, $message);
-is($changes[0]{pages}[0]{"page"}, "test2.mdwn");
-is($changes[1]{pages}[0]{"page"}, "test1.mdwn");
+is($changes[0]{pages}[0]{"page"}, "test2");
+is($changes[1]{pages}[0]{"page"}, "test1");
system "rm -rf $dir";
my @progs="ikiwiki.in";
my @libs="IkiWiki.pm";
# monotone, external, amazon_s3 skipped since they need perl modules
-push @libs, map { chomp; $_ } `find IkiWiki -type f -name \\*.pm | grep -v IkiWiki/Rcs/monotone.pm | grep -v IkiWiki/Plugin/external.pm | grep -v IkiWiki/Plugin/amazon_s3.pm`;
+push @libs, map { chomp; $_ } `find IkiWiki -type f -name \\*.pm | grep -v monotone.pm | grep -v external.pm | grep -v amazon_s3.pm | grep -v po.pm`;
+push @libs, 'IkiWiki/Plugin/skeleton.pm.example';
plan(tests => (@progs + @libs));
foreach my $file (@progs) {
- ok(system("perl -T -c $file >/dev/null 2>&1") eq 0, $file);
+ ok(system("perl -c $file >/dev/null 2>&1") eq 0, $file);
}
foreach my $file (@libs) {
ok(system("perl -c $file >/dev/null 2>&1") eq 0, $file);
--- /dev/null
+[[!inline pages="post" rss=yes]]
BEGIN { use_ok("IkiWiki"); }
-is(IkiWiki::titlepage("foo bar"), "foo_bar");
-is(IkiWiki::titlepage("foo bar baz"), "foo_bar_baz");
-is(IkiWiki::titlepage("foo bar/baz"), "foo_bar/baz");
-is(IkiWiki::titlepage("foo bar&baz"), "foo_bar__38__baz");
-is(IkiWiki::titlepage("foo bar & baz"), "foo_bar___38___baz");
-is(IkiWiki::titlepage("foo bar_baz"), "foo_bar__95__baz");
+is(titlepage("foo bar"), "foo_bar");
+is(titlepage("foo bar baz"), "foo_bar_baz");
+is(titlepage("foo bar/baz"), "foo_bar/baz");
+is(titlepage("foo bar&baz"), "foo_bar__38__baz");
+is(titlepage("foo bar & baz"), "foo_bar___38___baz");
+is(titlepage("foo bar_baz"), "foo_bar__95__baz");
--- /dev/null
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 10;
+
+BEGIN { use_ok("IkiWiki"); }
+
+# note: yesno always accepts English even if localized.
+# So no need to bother setting locale to C.
+
+ok(IkiWiki::yesno("yes") == 1);
+ok(IkiWiki::yesno("Yes") == 1);
+ok(IkiWiki::yesno("YES") == 1);
+
+ok(IkiWiki::yesno("no") == 0);
+ok(IkiWiki::yesno("No") == 0);
+ok(IkiWiki::yesno("NO") == 0);
+
+ok(IkiWiki::yesno("1") == 1);
+ok(IkiWiki::yesno("0") == 0);
+ok(IkiWiki::yesno("mooooooooooo") == 0);
<p>
+<TMPL_IF NAME="PERMALINK">
+<a href="<TMPL_VAR PERMALINK>"><TMPL_VAR TITLE></a><br />
+<TMPL_ELSE>
<a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a><br />
+</TMPL_IF>
<i>
Posted <TMPL_VAR CTIME>
+<TMPL_IF NAME="AUTHOR">
+by <span class="author">
+<TMPL_IF NAME="AUTHORURL">
+<a href="<TMPL_VAR AUTHORURL>"><TMPL_VAR AUTHOR></a>
+<TMPL_ELSE>
+<TMPL_VAR AUTHOR>
+</TMPL_IF>
+</span>
+</TMPL_IF>
</i>
-
</p>
<entry>
<title><TMPL_VAR TITLE></title>
- <id><TMPL_VAR URL></id>
+ <TMPL_IF NAME="GUID">
+ <id><TMPL_VAR GUID></id>
+ <TMPL_ELSE>
+ <id><TMPL_VAR URL></id>
+ </TMPL_IF>
<link href="<TMPL_VAR PERMALINK>"/>
<TMPL_IF NAME="AUTHOR">
<author><name><TMPL_VAR AUTHOR ESCAPE=HTML></name></author>
</TMPL_IF>
<TMPL_IF NAME="COPYRIGHT">
- <rights type="xhtml" xml:lang="en">
- <div xmlns="http://www.w3.org/1999/xhtml">
+ <rights type="html" xml:lang="en">
<TMPL_IF NAME="LICENSE">
- <TMPL_VAR LICENSE>
- <TMPL_VAR COPYRIGHT>
+ <TMPL_VAR LICENSE ESCAPE=HTML>
+ <TMPL_VAR COPYRIGHT ESCAPE=HTML>
<TMPL_ELSE>
- <TMPL_VAR COPYRIGHT>
+ <TMPL_VAR COPYRIGHT ESCAPE=HTML>
</TMPL_IF>
- </div>
</rights>
<TMPL_ELSE>
<TMPL_IF NAME="LICENSE">
- <rights type="xhtml" xml:lang="en">
- <div xmlns="http://www.w3.org/1999/xhtml">
- <TMPL_VAR LICENSE>
- </div>
+ <rights type="html" xml:lang="en">
+ <TMPL_VAR LICENSE ESCAPE=HTML>
</rights>
</TMPL_IF>
</TMPL_IF>
<TMPL_IF NAME="ENCLOSURE">
<link rel="enclosure" type="<TMPL_VAR TYPE>" href="<TMPL_VAR ENCLOSURE>" length="<TMPL_VAR LENGTH>" />
<TMPL_ELSE>
- <content type="xhtml" xml:lang="en">
- <div xmlns="http://www.w3.org/1999/xhtml">
- <TMPL_VAR CONTENT>
- </div>
+ <content type="html" xml:lang="en">
+ <TMPL_VAR CONTENT ESCAPE=HTML>
</content>
</TMPL_IF>
+ <TMPL_IF NAME="COMMENTSURL">
+ <link rel="comments" href="<TMPL_VAR NAME="COMMENTSURL">" type="text/html" />
+ </TMPL_IF>
+ <TMPL_IF NAME="ATOMCOMMENTSURL">
+ <link rel="comments" href="<TMPL_VAR NAME="ATOMCOMMENTSURL">" type="application/atom+xml" />
+ </TMPL_IF>
</entry>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><TMPL_VAR TITLE></title>
<link href="<TMPL_VAR PAGEURL>"/>
-<link href="<TMPL_VAR FEEDURL>" rel="self"/>
+<link href="<TMPL_VAR FEEDURL>" rel="self" type="application/atom+xml"/>
<author>
<TMPL_IF NAME="AUTHOR">
<name><TMPL_VAR AUTHOR></name>
</TMPL_IF>
</author>
<TMPL_IF NAME="COPYRIGHT">
- <rights type="xhtml" xml:lang="en">
- <div xmlns="http://www.w3.org/1999/xhtml">
+ <rights type="html" xml:lang="en">
<TMPL_IF NAME="LICENSE">
<TMPL_VAR LICENSE>
- <TMPL_VAR COPYRIGHT>
+ <TMPL_VAR COPYRIGHT ESCAPE=HTML>
<TMPL_ELSE>
- <TMPL_VAR COPYRIGHT>
+ <TMPL_VAR COPYRIGHT ESCAPE=HTML>
</TMPL_IF>
- </div>
</rights>
<TMPL_ELSE>
<TMPL_IF NAME="LICENSE">
- <rights type="xhtml" xml:lang="en">
- <div xmlns="http://www.w3.org/1999/xhtml">
- <TMPL_VAR LICENSE>
- </div>
+ <rights type="html">
+ <TMPL_VAR LICENSE ESCAPE=HTML>
</rights>
</TMPL_IF>
</TMPL_IF>
-<id><TMPL_VAR PAGEURL></id>
+<TMPL_IF NAME="GUID">
+ <id><TMPL_VAR GUID></id>
+<TMPL_ELSE>
+ <id><TMPL_VAR PAGEURL></id>
+</TMPL_IF>
<subtitle type="html"><TMPL_VAR FEEDDESC ESCAPE=HTML></subtitle>
<generator uri="http://ikiwiki.info/" version="<TMPL_VAR VERSION>">ikiwiki</generator>
<updated><TMPL_VAR FEEDDATE></updated>
--- /dev/null
+[[!map pages="<TMPL_VAR PAGE>/* and ! <TMPL_VAR PAGE>/*/*"]]
[[!meta authorurl="""<TMPL_VAR AUTHORURL>"""]]
</TMPL_IF>
[[!meta title="""change to<TMPL_LOOP NAME="PAGES"> <TMPL_VAR PAGE></TMPL_LOOP> on <TMPL_VAR WIKINAME>"""]]
-<div class="metadata">
+<TMPL_IF PERMALINK>
+[[!meta permalink="<TMPL_VAR PERMALINK>"]]
+</TMPL_IF>
+<div id="change-<TMPL_VAR REV>" class="metadata">
<span class="desc"><br />Changed pages:</span>
<span class="pagelinks">
<TMPL_LOOP NAME="PAGES">
<span class="desc"><br />Changed by:</span>
<span class="committer">
<TMPL_IF NAME="AUTHORURL">
-<a href="<TMPL_VAR AUTHORURL>"><TMPL_VAR USER></a>
+<a href="<TMPL_VAR AUTHORURL>" rel="nofollow"><TMPL_VAR USER></a>
<TMPL_ELSE>
<TMPL_VAR USER>
</TMPL_IF>
<span class="desc"><br />Commit type:</span>
<span class="committype"><TMPL_VAR COMMITTYPE></span>
<span class="desc"><br />Date:</span>
-<span class="changedate"><TMPL_VAR COMMITDATE></span>
+<span class="changedate"><TMPL_VAR COMMITDATE>
</div>
<div class=changelog>
<TMPL_LOOP NAME="MESSAGE">
<TMPL_IF NAME="LINE">
-<TMPL_VAR NAME="LINE" ESCAPE="HTML"><br />
+<TMPL_VAR NAME="LINE"><br />
</TMPL_IF>
</TMPL_LOOP>
</div>
<TMPL_IF NAME="DIFF">
<div class=diff>
<pre>
-<TMPL_VAR NAME="DIFF" ESCAPE="HTML">
+<TMPL_VAR NAME="DIFF">
</pre>
</div>
</TMPL_IF>
--- /dev/null
+<div class="comment" id="<TMPL_VAR NAME=COMMENTID>">
+
+<div class="comment-subject">
+<TMPL_IF PERMALINK>
+<a href="<TMPL_VAR PERMALINK>"><TMPL_VAR TITLE></a>
+<TMPL_ELSE>
+<TMPL_VAR TITLE>
+</TMPL_IF>
+</div>
+
+<div class="inlinecontent">
+<TMPL_VAR CONTENT>
+</div>
+
+<div class="comment-header">
+Comment by
+
+<TMPL_IF NAME="COMMENTUSER">
+<TMPL_IF NAME="COMMENTOPENID">
+<span class="author" title="OpenID">
+<a href="<TMPL_VAR NAME=COMMENTOPENID>"><TMPL_VAR NAME=COMMENTAUTHOR></a>
+</span>
+<TMPL_ELSE>
+<span class="author" title="Signed in">
+<TMPL_IF NAME="COMMENTAUTHORURL">
+<a href="<TMPL_VAR NAME=COMMENTAUTHORURL>"><TMPL_VAR NAME=COMMENTAUTHOR></a>
+<TMPL_ELSE>
+<TMPL_VAR NAME=COMMENTAUTHOR>
+</TMPL_IF>
+</span>
+</TMPL_IF>
+<TMPL_ELSE><!-- !COMMENTUSER -->
+<TMPL_IF NAME=COMMENTIP>
+<span class="author" title="Unauthenticated, from <TMPL_VAR NAME=COMMENTIP>">
+<TMPL_ELSE><!-- !COMMENTIP -->
+<span class="author" title="Unauthenticated, from unknown IP address">
+</TMPL_IF>
+<TMPL_IF NAME="AUTHORURL">
+<a href="<TMPL_VAR NAME=AUTHORURL>"><TMPL_VAR NAME=AUTHOR></a>
+<TMPL_ELSE>
+<TMPL_VAR NAME=AUTHOR>
+</TMPL_IF>
+</span>
+</TMPL_IF><!-- !COMMENTUSER -->
+
+— <TMPL_VAR CTIME>
+</div>
+
+<TMPL_IF NAME="HAVE_ACTIONS">
+<div class="actions">
+<ul>
+<TMPL_IF NAME="REMOVEURL">
+<li><a href="<TMPL_VAR REMOVEURL>" rel="nofollow">Remove comment</a></li>
+</TMPL_IF>
+</ul>
+</div><!--.actions-->
+</TMPL_IF>
+
+</div><!--.comment-->
--- /dev/null
+<TMPL_IF NAME="COMMENTS">
+<br />
+<form action="<TMPL_VAR CGIURL>" method="post">
+<input type="hidden" name="do" value="commentmoderation" />
+<input type="hidden" name="sid" value="<TMPL_VAR SID>" />
+<input type="submit" value="Submit" />
+<input type="checkbox" name="rejectalldefer" value="1" />Reject
+all comments marked <em>Defer</em>
+<br />
+<TMPL_LOOP NAME="COMMENTS">
+<div>
+<div>
+<TMPL_VAR VIEW>
+</div>
+<input type="radio" value="Defer" name="<TMPL_VAR ID>" checked />Defer
+<input type="radio" value="Accept" name="<TMPL_VAR ID>" />Accept
+<input type="radio" value="Reject" name="<TMPL_VAR ID>" />Reject
+</div>
+<br />
+</TMPL_LOOP>
+<input type="submit" value="Submit" />
+<input type="checkbox" name="rejectalldefer" value="1" />Reject
+all comments marked <em>Defer</em>
+</form>
+<TMPL_ELSE>
+<p>
+No comments need moderation at this time.
+</p>
+</TMPL_IF>
--- /dev/null
+<div class="editcomment">
+<TMPL_VAR MESSAGE>
+<TMPL_VAR FORM-START>
+<TMPL_VAR FIELD-DO>
+<TMPL_VAR FIELD-SID>
+<TMPL_VAR FIELD-PAGE>
+<TMPL_UNLESS NAME=USERNAME>
+<TMPL_IF NAME=ALLOWAUTHOR>
+Name: <TMPL_VAR NAME=FIELD-AUTHOR> (optional, or
+<a href="<TMPL_VAR SIGNINURL>">Signin</a>)<br />
+Website: <TMPL_VAR NAME=FIELD-URL> (optional)<br />
+<TMPL_ELSE>
+(You might want to <a href="<TMPL_VAR SIGNINURL>">Signin</a> first?)<br />
+</TMPL_IF>
+</TMPL_UNLESS>
+Subject: <TMPL_VAR FIELD-SUBJECT><br />
+<TMPL_VAR FIELD-EDITCONTENT><br />
+<TMPL_VAR FORM-SUBMIT> <TMPL_VAR FIELD-TYPE> <TMPL_VAR HELPONFORMATTINGLINK><br />
+<TMPL_VAR NAME="FORM-END">
+<TMPL_VAR WMD_PREVIEW>
+
+<TMPL_IF NAME="PAGE_PREVIEW">
+<hr />
+<div class="header">
+<span>Comment preview:</span>
+</div><!-- .header -->
+<div id="preview">
+<TMPL_VAR PAGE_PREVIEW>
+</div><!-- #preview -->
+</TMPL_IF>
+
+</div><!-- .editcomment -->
--- /dev/null
+<p class="error">
+<b>Your changes conflict with other changes made to the page.</b>
+</p>
+<p>
+Conflict markers have been inserted into the page content. Reconcile the
+conflict and commit again to save your changes.
+</p>
--- /dev/null
+<p class="error">
+<b>While you were creating this page, someone else independently created a page
+with the same name.</b>
+</p>
+<p>
+The edit box below contains the page's current content, followed by the
+content you entered previously, to allow you to merge the two
+together before saving.
+</p>
--- /dev/null
+<p class="error">
+<b>Failed to save your changes.</b>
+</p>
+<p>
+Your changes were not able to be saved to disk. The system gave the error:
+<blockquote>
+<TMPL_VAR ERROR_MESSAGE>
+</blockquote>
+Your changes are preserved below, and you can try again to save them.
+</p>
<br />
<TMPL_VAR JAVASCRIPT>
-<TMPL_IF NAME="PAGE_CONFLICT">
-<p>
-<b>Your changes conflict with other changes made to the page.</b>
-</p>
-<p>
-Conflict markers have been inserted into the page content. Reconcile the
-conflict and commit again to save your changes.
-</p>
-</TMPL_IF>
-<TMPL_IF NAME="FAILED_SAVE">
-<p>
-<b>Failed to save your changes.</b>
-</p>
-<p>
-Your changes were not able to be saved to disk. The system gave the error:
-<blockquote>
-<TMPL_VAR ERROR_MESSAGE>
-</blockquote>
-Your changes are preserved below, and you can try again to save them.
-</p>
-</TMPL_IF>
-<TMPL_IF NAME="PAGE_GONE">
-<p>
-<b>The page you were editing has disappeared.</b>
-</p>
-<p>
-Perhaps someone else has deleted it or moved it. If you want to recreate
-this page with your text, click "Save Page" again.
-</p>
-</TMPL_IF>
-<TMPL_IF NAME="CREATION_CONFLICT">
-<p>
-<b>While you were creating this page, someone else independently created a page
-with the same name.</b>
-</p>
-<p>
-The edit box below contains the page's current content, followed by the
-content you entered previously, to allow you to merge the two
-together before saving.
-</p>
-</TMPL_IF>
+<TMPL_VAR MESSAGE>
<TMPL_VAR FORM-START>
<TMPL_VAR FIELD-DO>
<TMPL_VAR FIELD-SID>
</TMPL_IF>
<TMPL_VAR FORM-SUBMIT>
<TMPL_VAR HELPONFORMATTINGLINK>
-<a class="toggle" href="#attachments">Attachments</a>
<TMPL_IF NAME="FIELD-ATTACHMENT">
+<a class="toggle" href="#attachments">Attachments</a>
<div class="<TMPL_VAR ATTACHMENTS-CLASS>" id="attachments">
<table>
<tr><td colspan="5"><TMPL_VAR FIELD-ATTACHMENT><TMPL_VAR FIELD-UPLOAD></td></tr>
<tr><td><TMPL_VAR FIELD-SELECT><TMPL_VAR LINK></td><td><TMPL_VAR SIZE></td><td><TMPL_VAR MTIME></td></tr>
</TMPL_LOOP>
<TMPL_IF NAME="ATTACHMENT_LIST">
-<tr><td colspan="2"><TMPL_VAR FIELD-LINK><TMPL_VAR FIELD-DELETE><TMPL_VAR FIELD-RENAME></td></tr>
+<tr><td colspan="2"><TMPL_VAR FIELD-LINK><TMPL_VAR FIELD-RENAME><TMPL_VAR FIELD-REMOVE></td></tr>
</TMPL_IF>
</table>
</div>
</TMPL_IF>
<TMPL_VAR FORM-END>
+<TMPL_VAR WMD_PREVIEW>
<TMPL_IF NAME="PAGE_PREVIEW">
<hr />
--- /dev/null
+<p class="error">
+<b>The page you were editing has disappeared.</b>
+</p>
+<p>
+Perhaps someone else has deleted it or moved it. If you want to recreate
+this page with your text, click "Save Page" again.
+</p>
+++ /dev/null
-indexname: <TMPL_VAR INDEX>
-tmplfile: <TMPL_VAR TMPLFILE>
-topfile: /dev/null
-logfile:
-logformat:
-replace: ^file://<TMPL_VAR DESTDIR>{{!}}<TMPL_VAR URL>
-showreal: false
-perpage: 10,20,30,40,50,100
-attrselect: false
-showscore: false
-extattr: date|Date
-snipwwidth: 480
-sniphwidth: 96
-snipawidth: 96
-condgstep: 2
-dotfidf: true
-scancheck: false
-smplphrase: true
-phraseform: 2
-candetail: true
-smlrvnum: 0
-smlrtune: 16 1024 4096
-clipview: 2
-relkeynum: 0
-spcache:
-wildmax: 256
-qxpndcmd:
-helpfile: /usr/share/hyperestraier/estseek.help
-deftitle:
-attrwidth: 80
-dispproxy:
--- /dev/null
+<form method="get" action="http://www.google.com/search" id="searchform">
+ <div>
+ <input name="sitesearch" value="<TMPL_VAR SITEFQDN>" type="hidden" />
+ <input name="q" value="" id="searchbox" size="16" maxlength="255" type="text" />
+ </div>
+</form>
<div class="inlinepage">
+
+<div class="inlineheader">
+
<TMPL_IF NAME="AUTHOR">
<span class="author">
<TMPL_IF NAME="AUTHORURL">
-<a href="<TMPL_VAR NAME=AUTHORURL>"><TMPL_VAR NAME=AUTHOR></a>
+<a href="<TMPL_VAR AUTHORURL>"><TMPL_VAR AUTHOR></a>
<TMPL_ELSE>
-<TMPL_VAR NAME=AUTHOR>
+<TMPL_VAR AUTHOR>
</TMPL_IF>
</span>
</TMPL_IF>
<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>
<span class="tags">
Tags:
<TMPL_LOOP NAME="TAGS">
-<TMPL_VAR NAME=LINK>
+<TMPL_VAR LINK>
</TMPL_LOOP>
</span>
</TMPL_IF>
<TMPL_IF NAME="EDITURL">
<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>
</TMPL_IF>
+<TMPL_IF NAME="COMMENTSLINK">
+<li><TMPL_VAR COMMENTSLINK></li>
+<TMPL_ELSE>
<TMPL_IF NAME="DISCUSSIONLINK">
<li><TMPL_VAR DISCUSSIONLINK></li>
</TMPL_IF>
+</TMPL_IF>
</ul>
-</div>
+</div><!--.actions-->
</TMPL_IF>
-</div>
+</div><!--.inlinefooter-->
+
+</div><!--.inlinepage-->
--- /dev/null
+<div class="microblog">
+
+<div class="inlinecontent">
+<TMPL_VAR CONTENT>
+</div>
+
+<div class="microblog-header">
+
+<TMPL_IF NAME="AUTHOR">
+<span class="author">
+<TMPL_IF NAME="AUTHORURL">
+<a href="<TMPL_VAR AUTHORURL>"><TMPL_VAR AUTHOR></a>
+<TMPL_ELSE>
+<TMPL_VAR AUTHOR>
+</TMPL_IF>
+</span>
+</TMPL_IF>
+
+— <TMPL_VAR CTIME>
+
+</div> <!--.microblog-header-->
+</div> <!--.microblog-->
</head>
<body>
+<div class="pageheader">
<div class="header">
<span>
<TMPL_VAR INDEXLINK>/ <TMPL_VAR TITLE>
</span>
</div>
+</div> <!-- .pageheader -->
<div id="content">
<TMPL_VAR PAGEBODY>
<link rel="alternate" type="application/x-wiki" title="Edit this page" href="<TMPL_VAR EDITURL>" />
</TMPL_IF>
<TMPL_IF NAME="FEEDLINKS"><TMPL_VAR FEEDLINKS></TMPL_IF>
+<TMPL_IF NAME="RELVCS"><TMPL_VAR RELVCS></TMPL_IF>
<TMPL_IF NAME="META"><TMPL_VAR META></TMPL_IF>
</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>/
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>/
</TMPL_LOOP>
+</span>
+<span class="title">
<TMPL_VAR TITLE>
+<TMPL_IF NAME="ISTRANSLATION">
+ (<TMPL_VAR NAME="PERCENTTRANSLATED">%)
+</TMPL_IF>
</span>
+</span><!--.header-->
<TMPL_IF NAME="SEARCHFORM">
<TMPL_VAR SEARCHFORM>
</TMPL_IF>
<TMPL_IF NAME="HISTORYURL">
<li><a href="<TMPL_VAR HISTORYURL>">History</a></li>
</TMPL_IF>
+<TMPL_IF NAME="GETSOURCEURL">
+<li><a href="<TMPL_VAR GETSOURCEURL>">Source</a></li>
+</TMPL_IF>
<TMPL_IF NAME="PREFSURL">
<li><a href="<TMPL_VAR PREFSURL>">Preferences</a></li>
</TMPL_IF>
+<TMPL_IF NAME="COMMENTSLINK">
+<li><TMPL_VAR COMMENTSLINK><br /></li>
+<TMPL_ELSE>
<TMPL_IF NAME="DISCUSSIONLINK">
<li><TMPL_VAR DISCUSSIONLINK><br /></li>
</TMPL_IF>
+</TMPL_IF>
</ul>
</div>
</TMPL_IF>
+<TMPL_IF NAME="OTHERLANGUAGES">
+<div id="otherlanguages">
+<ul>
+<TMPL_LOOP NAME="OTHERLANGUAGES">
+<li>
+<a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="LANGUAGE"></a>
+<TMPL_IF NAME="MASTER">
+(master)
+<TMPL_ELSE>
+ (<TMPL_VAR NAME="PERCENT">%)
+</TMPL_IF>
+</li>
+</TMPL_LOOP>
+</ul>
+</div> <!-- #otherlanguages -->
+</TMPL_IF>
+
+</div> <!-- .pageheader -->
+
<TMPL_IF SIDEBAR>
<div id="sidebar">
<TMPL_VAR SIDEBAR>
<TMPL_VAR CONTENT>
</div>
-<div id="footer">
+<TMPL_IF COMMENTS>
+<div id="comments">
+<TMPL_VAR COMMENTS>
+<TMPL_IF ADDCOMMENTURL>
+<div class="addcomment">
+<a href="<TMPL_VAR ADDCOMMENTURL>">Add a comment</a>
+</div>
+<TMPL_ELSE>
+<div class="addcomment">Comments on this page are closed.</div>
+</TMPL_IF>
+</div>
+</TMPL_IF>
+
+<div id="footer" class="pagefooter">
<div id="pageinfo">
<TMPL_IF NAME="TAGS">
<div class="tags">
Tags:
<TMPL_LOOP NAME="TAGS">
-<TMPL_VAR NAME=LINK>
+<TMPL_VAR LINK>
</TMPL_LOOP>
</div>
</TMPL_IF>
<div id="backlinks">
Links:
<TMPL_LOOP NAME="BACKLINKS">
-<a href="<TMPL_VAR NAME=URL>"><TMPL_VAR NAME=PAGE></a>
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>
</TMPL_LOOP>
<TMPL_IF NAME="MORE_BACKLINKS">
<span class="popup">...
<span class="balloon">
<TMPL_LOOP NAME="MORE_BACKLINKS">
-<a href="<TMPL_VAR NAME=URL>"><TMPL_VAR NAME=PAGE></a>
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>
</TMPL_LOOP>
</span>
</span>
</TMPL_IF>
-</div>
+</div><!-- #backlinks -->
</TMPL_IF>
<TMPL_IF COPYRIGHT>
</TMPL_IF>
<div class="pagedate">
-Last edited <TMPL_VAR NAME=MTIME>
-<!-- Created <TMPL_VAR NAME=CTIME> -->
+Last edited <TMPL_VAR MTIME>
+<!-- Created <TMPL_VAR CTIME> -->
</div>
-</div>
+</div><!-- #pageinfo -->
<TMPL_IF EXTRAFOOTER><TMPL_VAR EXTRAFOOTER></TMPL_IF>
-<!-- from <TMPL_VAR NAME=WIKINAME> -->
-</div>
+<!-- from <TMPL_VAR WIKINAME> -->
+</div><!-- .pagefooter #footer -->
</body>
</html>
--- /dev/null
+<p>
+<b>WARNING</b> this page must be written in <TMPL_VAR NAME="LANG">.
+</p>
\ No newline at end of file
--- /dev/null
+<TMPL_IF ERROR>
+<p>
+<b>Failed to rename <TMPL_VAR SRC> to <TMPL_VAR DEST>: </b>
+<TMPL_VAR ERROR>
+</p>
+<TMPL_ELSE>
+<p>
+<b>Successfully renamed <TMPL_VAR SRC> to <TMPL_VAR DEST>.</b>
+</p>
+<p>
+<TMPL_IF FIXEDLINKS>
+The following pages have been automatically modified to update their links to <TMPL_VAR DEST>:
+<ul>
+<TMPL_LOOP NAME=FIXEDLINKS><li><TMPL_VAR PAGE></li></TMPL_LOOP>
+</ul>
+</TMPL_IF>
+<TMPL_IF BROKENLINKS_CHECKED>
+<TMPL_IF BROKENLINKS>
+The following pages still link to <TMPL_VAR SRC>:
+<ul>
+<TMPL_LOOP NAME=BROKENLINKS><li><TMPL_VAR PAGE></li></TMPL_LOOP>
+</ul>
+</TMPL_IF>
+</TMPL_IF>
+</p>
+</TMPL_IF>
<TMPL_ELSE>
<title><TMPL_VAR TITLE></title>
</TMPL_IF>
- <guid><TMPL_VAR URL></guid>
+ <TMPL_IF NAME="GUID">
+ <guid isPermaLink="no"><TMPL_VAR GUID></guid>
+ <TMPL_ELSE>
+ <guid><TMPL_VAR URL></guid>
+ </TMPL_IF>
<link><TMPL_VAR PERMALINK></link>
<TMPL_IF NAME="CATEGORIES">
<TMPL_LOOP NAME="CATEGORIES">
<TMPL_IF NAME="ENCLOSURE">
<enclosure url="<TMPL_VAR ENCLOSURE>" type="<TMPL_VAR TYPE>" length="<TMPL_VAR LENGTH>" />
<TMPL_ELSE>
- <description><![CDATA[<TMPL_VAR CONTENT>]]></description>
+ <description><TMPL_VAR CONTENT ESCAPE=HTML></description>
+ </TMPL_IF>
+ <TMPL_IF NAME="COMMENTSURL">
+ <comments><TMPL_VAR NAME="COMMENTSURL"></comments>
</TMPL_IF>
</item>
<form method="get" action="<TMPL_VAR SEARCHACTION>" id="searchform">
<div>
-<input type="text" name="P" value="" size="16" />
+<input type="text" id="searchbox" name="P" value="" size="16" />
</div>
</form>
$setmap{prefix,title,S}
-$setmap{prefix,link,LINK}
+$setmap{prefix,link,XLINK}
$set{thousand,$.}$set{decimal,.}$setmap{BN,,Any Country,uk,England,fr,France}
${
$def{PREV,
-<p><a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a></p>
+<p>
+<TMPL_IF NAME="PERMALINK">
+<a href="<TMPL_VAR PERMALINK>"><TMPL_VAR TITLE></a>
+<TMPL_ELSE>
+<a href="<TMPL_VAR PAGEURL>"><TMPL_VAR TITLE></a>
+</TMPL_IF>
+</p>
+++ /dev/null
-[[!meta redir=ikiwiki/blog delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/blog|ikiwiki/blog]]. Please update your
-links, as this redirection page will be removed in a future ikiwiki
-release.
+++ /dev/null
-[[!meta redir=ikiwiki/formatting delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/formatting|ikiwiki/formatting]]. Please
-update your links, as this redirection page will be removed in a future
-ikiwiki release.
+++ /dev/null
-../../../doc/ikiwiki/blog.mdwn
\ No newline at end of file
--- /dev/null
+../../../doc/ikiwiki/directive.mdwn
\ No newline at end of file
--- /dev/null
+../../../../doc/ikiwiki/pagespec/po.mdwn
\ No newline at end of file
+++ /dev/null
-../../../doc/ikiwiki/preprocessordirective.mdwn
\ No newline at end of file
+++ /dev/null
-../../../doc/ikiwiki/subpage
\ No newline at end of file
--- /dev/null
+../../../../doc/ikiwiki/subpage/linkingrules.mdwn
\ No newline at end of file
+++ /dev/null
-[[!meta redir=ikiwiki/markdown delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/markdown|ikiwiki/markdown]]. Please update
-your links, as this redirection page will be removed in a future ikiwiki
-release.
+++ /dev/null
-[[!meta redir=ikiwiki/openid delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/openid|ikiwiki/openid]]. Please update your
-links, as this redirection page will be removed in a future ikiwiki
-release.
+++ /dev/null
-[[!meta redir=ikiwiki/pagespec delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/pagespec|ikiwiki/pagespec]]. Please update
-your links, as this redirection page will be removed in a future ikiwiki
-release.
+++ /dev/null
-[[!meta redir=ikiwiki/preprocessordirective delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to
-[[ikiwiki/preprocessordirective|ikiwiki/preprocessordirective]]. Please
-update your links, as this redirection page will be removed in a future
-ikiwiki release.
+++ /dev/null
-[[!meta redir=ikiwiki/subpage delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/subpage|ikiwiki/subpage]]. Please update your
-links, as this redirection page will be removed in a future ikiwiki
-release.
+++ /dev/null
-[[!meta redir=ikiwiki/wikilink delay=10]]
-[[!meta robots="noindex, follow"]]
-
-This page has moved to [[ikiwiki/wikilink|ikiwiki/wikilink]]. Please update
-your links, as this redirection page will be removed in a future ikiwiki
-release.
--- /dev/null
+// ikiwiki's javascript utility function library
+
+var hooks;
+
+// Run onload as soon as the DOM is ready, if possible.
+// gecko, opera 9
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", run_hooks_onload, false);
+}
+// other browsers
+window.onload = run_hooks_onload;
+
+function run_hooks_onload() {
+ // avoid firing twice
+ if (arguments.callee.done)
+ return;
+ arguments.callee.done = true;
+
+ run_hooks("onload");
+}
+
+function run_hooks(name) {
+ if (typeof(hooks) != "undefined") {
+ for (var i = 0; i < hooks.length; i++) {
+ if (hooks[i].name == name) {
+ hooks[i].call();
+ }
+ }
+ }
+}
+
+function hook(name, call) {
+ if (typeof(hooks) == "undefined")
+ hooks = new Array;
+ hooks.push({name: name, call: call});
+}
+
+function getElementsByClass(cls, node, tag) {
+ if (document.getElementsByClass)
+ return document.getElementsByClass(cls, node, tag);
+ if (! node) node = document;
+ if (! tag) tag = '*';
+ var ret = new Array();
+ var pattern = new RegExp("(^|\\s)"+cls+"(\\s|$)");
+ var els = node.getElementsByTagName(tag);
+ for (i = 0; i < els.length; i++) {
+ if ( pattern.test(els[i].className) ) {
+ ret.push(els[i]);
+ }
+ }
+ return ret;
+}
--- /dev/null
+// Causes html elements in the 'relativedate' class to be displayed
+// as relative dates. The date is parsed from the title attribute, or from
+// the element content.
+
+var dateElements;
+
+hook("onload", getDates);
+
+function getDates() {
+ dateElements = getElementsByClass('relativedate');
+ for (var i = 0; i < dateElements.length; i++) {
+ var elt = dateElements[i];
+ var title = elt.attributes.title;
+ var d = new Date(title ? title.value : elt.innerHTML);
+ if (! isNaN(d)) {
+ dateElements[i].date=d;
+ elt.title=elt.innerHTML;
+ }
+ }
+
+ showDates();
+}
+
+function showDates() {
+ for (var i = 0; i < dateElements.length; i++) {
+ var elt = dateElements[i];
+ var d = elt.date;
+ if (! isNaN(d)) {
+ elt.innerHTML=relativeDate(d);
+ }
+ }
+ setTimeout(showDates,30000); // keep updating every 30s
+}
+
+var timeUnits = new Array;
+timeUnits['minute'] = 60;
+timeUnits['hour'] = timeUnits['minute'] * 60;
+timeUnits['day'] = timeUnits['hour'] * 24;
+timeUnits['month'] = timeUnits['day'] * 30;
+timeUnits['year'] = timeUnits['day'] * 364;
+var timeUnitOrder = ['year', 'month', 'day', 'hour', 'minute'];
+
+function relativeDate(date) {
+ var now = new Date();
+ var offset = date.getTime() - now.getTime();
+ var seconds = Math.round(Math.abs(offset) / 1000);
+
+ // hack to avoid reading just in the future if there is a minor
+ // amount of clock slip
+ if (offset >= 0 && seconds < 30 * timeUnits['minute']) {
+ return "just now";
+ }
+
+ var ret = "";
+ var shown = 0;
+ for (i = 0; i < timeUnitOrder.length; i++) {
+ var unit = timeUnitOrder[i];
+ if (seconds >= timeUnits[unit]) {
+ var num = Math.floor(seconds / timeUnits[unit]);
+ seconds -= num * timeUnits[unit];
+ if (ret)
+ ret += "and ";
+ ret += num + " " + unit + (num > 1 ? "s" : "") + " ";
+
+ if (++shown == 2)
+ break;
+ }
+ else if (shown)
+ break;
+ }
+
+ if (! ret)
+ ret = "less than a minute "
+
+ return ret + (offset < 0 ? "ago" : "from now");
+}
--- /dev/null
+// Uses CSS to hide toggleables, to avoid any flashing on page load. The
+// CSS is only emitted after it tests that it's going to be able
+// to show the toggleables.
+if (document.getElementById && document.getElementsByTagName && document.createTextNode) {
+ document.write('<style type="text/css">div.toggleable { display: none; }</style>');
+ hook("onload", inittoggle);
+}
+
+function inittoggle() {
+ var as = getElementsByClass('toggle');
+ for (var i = 0; i < as.length; i++) {
+ var id = as[i].href.match(/#(\w.+)/)[1];
+ if (document.getElementById(id).className == "toggleable")
+ document.getElementById(id).style.display="none";
+ as[i].onclick = function() {
+ toggle(this);
+ return false;
+ }
+ }
+}
+
+function toggle(s) {
+ var id = s.href.match(/#(\w.+)/)[1];
+ style = document.getElementById(id).style;
+ if (style.display == "none")
+ style.display = "block";
+ else
+ style.display = "none";
+}