diff options
-rw-r--r-- | IkiWiki.pm | 1 | ||||
-rw-r--r-- | IkiWiki/CGI.pm | 10 | ||||
-rw-r--r-- | IkiWiki/Plugin/attachment.pm | 346 | ||||
-rw-r--r-- | IkiWiki/Plugin/editdiff.pm | 3 | ||||
-rw-r--r-- | IkiWiki/Plugin/lockedit.pm | 8 | ||||
-rw-r--r-- | IkiWiki/Plugin/toggle.pm | 24 | ||||
-rw-r--r-- | IkiWiki/Render.pm | 43 | ||||
-rw-r--r-- | debian/changelog | 13 | ||||
-rw-r--r-- | doc/plugins/attachment.mdwn | 64 | ||||
-rw-r--r-- | doc/plugins/contrib/attach/discussion.mdwn | 18 | ||||
-rw-r--r-- | doc/plugins/toggle.mdwn | 3 | ||||
-rw-r--r-- | doc/soc.mdwn | 2 | ||||
-rw-r--r-- | doc/todo/attachments.mdwn | 16 | ||||
-rw-r--r-- | doc/todo/attachments_plugin.mdwn | 1 | ||||
-rw-r--r-- | doc/todo/fileupload.mdwn | 2 | ||||
-rw-r--r-- | doc/todo/toggle_initial_state.mdwn | 2 | ||||
-rw-r--r-- | templates/editpage.tmpl | 15 |
17 files changed, 525 insertions, 46 deletions
diff --git a/IkiWiki.pm b/IkiWiki.pm index 7d5668d74..d9b3dcdb4 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -88,6 +88,7 @@ sub defaultconfig () { #{{{ account_creation_password => "", prefix_directives => 0, hardlink => 0, + cgi_disable_uploads => 1, } #}}} sub checkconfig () { #{{{ diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 015c9ae01..07e92322f 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -281,7 +281,6 @@ sub cgi_editpage ($$) { #{{{ eval q{use CGI::FormBuilder}; error($@) if $@; my $form = CGI::FormBuilder->new( - title => "editpage", fields => \@fields, charset => "utf-8", method => 'POST', @@ -304,7 +303,7 @@ sub cgi_editpage ($$) { #{{{ # This untaint is safe because titlepage removes any problematic # characters. - my ($page)=$form->field('page'); + my $page=$form->field('page'); $page=titlepage(possibly_foolish_untaint($page)); if (! defined $page || ! length $page || file_pruned($page, $config{srcdir}) || $page=~/^\//) { @@ -667,10 +666,11 @@ sub cgi (;$$) { #{{{ my $q=shift; my $session=shift; + eval q{use CGI}; + error($@) if $@; + $CGI::DISABLE_UPLOADS=$config{cgi_disable_uploads}; + if (! $q) { - eval q{use CGI}; - error($@) if $@; - binmode(STDIN); $q=CGI->new; binmode(STDIN, ":utf8"); diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm new file mode 100644 index 000000000..a5c42d638 --- /dev/null +++ b/IkiWiki/Plugin/attachment.pm @@ -0,0 +1,346 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::attachment; + +use warnings; +use strict; +use IkiWiki 2.00; + +sub import { #{{{ + hook(type => "checkconfig", id => "attachment", call => \&checkconfig); + hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup); + hook(type => "formbuilder", id => "attachment", call => \&formbuilder); +} # }}} + +sub checkconfig () { #{{{ + $config{cgi_disable_uploads}=0; +} #}}} + +sub formbuilder_setup (@) { #{{{ + my %params=@_; + my $form=$params{form}; + my $q=$params{cgi}; + + if ($form->field("do") eq "edit") { + $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. + require IkiWiki::Plugin::toggle; + $form->tmpl_param("javascript" => $IkiWiki::Plugin::toggle::javascript); + # 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")) { + $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", noimageinline => 1).")"); + 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 (@) { #{{{ + my %params=@_; + my $form=$params{form}; + my $q=$params{cgi}; + + return if $form->field("do") ne "edit"; + + my $filename=$q->param('attachment'); + if (defined $filename && length $filename && + ($form->submitted eq "Upload Attachment" || $form->submitted eq "Save Page")) { + my $session=$params{session}; + + # 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( + attachment_location($form->field('page')). + IkiWiki::basename($filename))); + if (IkiWiki::file_pruned($filename, $config{srcdir})) { + error(gettext("bad attachment filename")); + } + + # 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)"); + } + + # Needed for fast_file_copy and for rendering below. + require IkiWiki::Render; + + # Move the attachment into place. + # Try to use a fast rename; fall back to copying. + IkiWiki::prep_writefile($filename, $config{srcdir}); + unlink($config{srcdir}."/".$filename); + if (rename($tempfile, $config{srcdir}."/".$filename)) { + # The temp file has tight permissions; loosen up. + chmod(0666 & ~umask, $config{srcdir}."/".$filename); + } + else { + my $fh=$q->upload('attachment'); + if (! defined $fh || ! ref $fh) { + error("failed to get filehandle"); + } + binmode($fh); + writefile($filename, $config{srcdir}, undef, 1, sub { + IkiWiki::fast_file_copy($tempfile, $filename, $fh, @_); + }); + } + + # Check the attachment in and trigger a wiki refresh. + if ($config{rcs}) { + IkiWiki::rcs_add($filename); + IkiWiki::disable_commit_hook(); + IkiWiki::rcs_commit($filename, gettext("attachment upload"), + IkiWiki::rcs_prepedit($filename), + $session->param("name"), $ENV{REMOTE_ADDR}); + IkiWiki::enable_commit_hook(); + IkiWiki::rcs_update(); + } + IkiWiki::refresh(); + IkiWiki::saveindex(); + } + elsif ($form->submitted eq "Insert Links") { + my $add=""; + foreach my $f ($q->param("attachment_select")) { + $add.="[[$f]]\n"; + } + $form->field(name => 'editcontent', + value => $form->field('editcontent')."\n\n".$add, + force => 1) if length $add; + } + + # 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; + + # Put the attachment in a subdir of the page it's attached + # to, unless that page is an "index" page. + $page=~s/(^|\/)index//; + $page.="/" if length $page; + + return $page; +} + +sub attachment_list ($) { + my $page=shift; + my $loc=attachment_location($page); + + my @ret; + foreach my $f (values %pagesources) { + if (! defined IkiWiki::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]), + mtime => displaytime($IkiWiki::pagemtime{$f}), + mtime_raw => $IkiWiki::pagemtime{$f}, + }; + } + } + + # Sort newer attachments to the top of the list, so a newly-added + # attachment appears just before the form used to add it. + 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_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 diff --git a/IkiWiki/Plugin/editdiff.pm b/IkiWiki/Plugin/editdiff.pm index 2a70ca0b8..b8ecaa3d7 100644 --- a/IkiWiki/Plugin/editdiff.pm +++ b/IkiWiki/Plugin/editdiff.pm @@ -48,8 +48,7 @@ sub formbuilder_setup { #{{{ my $form=$params{form}; my $page=$form->field("page"); - return if $form->title ne "editpage" - || $form->field("do") ne "edit"; + return if $form->field("do") ne "edit"; $page = IkiWiki::titlepage(IkiWiki::possibly_foolish_untaint($page)); return unless exists $pagesources{$page}; diff --git a/IkiWiki/Plugin/lockedit.pm b/IkiWiki/Plugin/lockedit.pm index 010705c49..5ffb4e6f9 100644 --- a/IkiWiki/Plugin/lockedit.pm +++ b/IkiWiki/Plugin/lockedit.pm @@ -40,11 +40,11 @@ sub formbuilder_setup (@) { #{{{ my %params=@_; my $form=$params{form}; - my $session=$params{session}; - my $cgi=$params{cgi}; - my $user_name=$session->param("name"); - 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).")"); diff --git a/IkiWiki/Plugin/toggle.pm b/IkiWiki/Plugin/toggle.pm index 8089443e0..284eb8249 100644 --- a/IkiWiki/Plugin/toggle.pm +++ b/IkiWiki/Plugin/toggle.pm @@ -9,7 +9,7 @@ use IkiWiki 2.00; # 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. -my $javascript=<<'EOF'; +our $javascript=<<'EOF'; <script type="text/javascript"> <!-- if (document.getElementById && document.getElementsByTagName && document.createTextNode) { @@ -21,7 +21,8 @@ function inittoggle() { var as = getElementsByClass('toggle'); for (var i = 0; i < as.length; i++) { var id = as[i].href.match(/#(\w.+)/)[1]; - document.getElementById(id).style.display="none"; + if (document.getElementById(id).className == "toggleable") + document.getElementById(id).style.display="none"; as[i].onclick = function() { toggle(this); return false; @@ -80,17 +81,11 @@ sub preprocess_toggle (@) { #{{{ my %params=(id => "default", text => "more", @_); my $id=genid($params{page}, $params{id}); - if (! $params{preview}) { - return "<a class=\"toggle\" href=\"#$id\">$params{text}</a>"; - } - else { - return "$params{text} ". - gettext("(not toggleable in preview mode)"); - } + return "<a class=\"toggle\" href=\"#$id\">$params{text}</a>"; } # }}} sub preprocess_toggleable (@) { #{{{ - my %params=(id => "default", text => "", @_); + my %params=(id => "default", text => "", open => "no", @_); # Preprocess the text to expand any preprocessor directives # embedded inside it. @@ -98,23 +93,24 @@ sub preprocess_toggleable (@) { #{{{ IkiWiki::filter($params{page}, $params{destpage}, $params{text})); my $id=genid($params{page}, $params{id}); + my $class=(lc($params{open}) ne "yes") ? "toggleable" : "toggleable-open"; # Should really be a postprocessor directive, oh well. Work around # markdown's dislike of markdown inside a <div> with various funky # whitespace. my ($indent)=$params{text}=~/( +)$/; $indent="" unless defined $indent; - return "<div class=\"toggleable\" id=\"$id\"></div>\n\n$params{text}\n$indent<div class=\"toggleableend\"></div>"; + return "<div class=\"$class\" id=\"$id\"></div>\n\n$params{text}\n$indent<div class=\"toggleableend\"></div>"; } # }}} sub format (@) { #{{{ my %params=@_; - if ($params{content}=~s!(<div class="toggleable" id="[^"]+">)</div>!$1!g) { + if ($params{content}=~s!(<div class="toggleable(?:-open)?" id="[^"]+">)</div>!$1!g) { $params{content}=~s/<div class="toggleableend">//g; - if (! ($params{content}=~s!^<\/body>!$javascript</body>!m)) { + if (! ($params{content}=~s!^<body>!<body>$javascript!m)) { # no </body> tag, probably in preview mode - $params{content}.=$javascript; + $params{content}=$javascript.$params{content}; } } return $params{content}; diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 272eb239a..5184be2df 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -180,6 +180,30 @@ sub scan ($) { #{{{ } } #}}} +sub fast_file_copy (@) { #{{{ + my $srcfile=shift; + my $destfile=shift; + my $srcfd=shift; + my $destfd=shift; + my $cleanup=shift; + + my $blksize = 16384; + my ($len, $buf, $written); + while ($len = sysread $srcfd, $buf, $blksize) { + if (! defined $len) { + next if $! =~ /^Interrupted/; + error("failed to read $srcfile: $!", $cleanup); + } + my $offset = 0; + while ($len) { + defined($written = syswrite $destfd, $buf, $len, $offset) + or error("failed to write $destfile: $!", $cleanup); + $len -= $written; + $offset += $written; + } + } +} + sub render ($) { #{{{ my $file=shift; @@ -215,24 +239,7 @@ sub render ($) { #{{{ my $srcfd=readfile($srcfile, 1, 1); writefile($file, $config{destdir}, undef, 1, sub { - my $destfd=shift; - my $cleanup=shift; - - my $blksize = 16384; - my ($len, $buf, $written); - while ($len = sysread $srcfd, $buf, $blksize) { - if (! defined $len) { - next if $! =~ /^Interrupted/; - error("failed to read $srcfile: $!", $cleanup); - } - my $offset = 0; - while ($len) { - defined($written = syswrite $destfd, $buf, $len, $offset) - or error("failed to write $file: $!", $cleanup); - $len -= $written; - $offset += $written; - } - } + fast_file_copy($srcfile, $file, $srcfd, @_); }); } } #}}} diff --git a/debian/changelog b/debian/changelog index 9153254b4..e6ffa17de 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +ikiwiki (2.52) UNRELEASED; urgency=low + + * attachment: New plugin for uploading and managing attachments. + (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. + + -- Joey Hess <joeyh@debian.org> Mon, 30 Jun 2008 19:56:28 -0400 + ikiwiki (2.51) unstable; urgency=low * Improve toplevel parentlink to link directly to index.html when usedirs is diff --git a/doc/plugins/attachment.mdwn b/doc/plugins/attachment.mdwn new file mode 100644 index 000000000..184f5b5df --- /dev/null +++ b/doc/plugins/attachment.mdwn @@ -0,0 +1,64 @@ +[[template id=plugin name=conditional core=1 author="[[Joey]]"]] +[[tag type/useful]] + +This plugin allows files to be uploaded to the wiki over the web. + +For each page `foo`, files in the subdirectory `foo/` are treated as +attachments of that page. Attachments can be uploaded and managed as +part of the interface for editing a page. + +Warning: Do not enable this plugin on publically editable wikis, unless you +take care to lock down the types and sizes of files that can be uploaded. +Bear in mind that if you let anyone upload a particular kind of file +("*.mp3" files, say), then someone can abuse your wiki in at least three ways: + +1. By uploading many mp3 files, wasting your disk space. +2. By uploading mp3 files that attempt to exploit security holes + in web browsers or other players. +3. By uploading files that claim to be mp3 files, but are really some + other kind of file. Some web browsers may display a `foo.mp3` that + contains html as a web page; including running any malicious javascript + embedded in that page. + +To provide a way to combat these abuses, the wiki admin can specify a +[[ikiwiki/PageSpec]] on their preferences page, to control what types of +attachments can be uploaded, and by whom. The regular [[ikiwiki/PageSpec]] +syntax is expanded with additional tests. + +For example, to limit arbitrary files to 50 kilobytes, but allow +larger mp3 files to be uploaded by joey, a test like this could be +used: + + (user(joey) and *.mp3 and maxsize(15mb)) or (!ispage() and maxsize(50kb)) + +The following additional tests are available: + +* 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() + + 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. diff --git a/doc/plugins/contrib/attach/discussion.mdwn b/doc/plugins/contrib/attach/discussion.mdwn new file mode 100644 index 000000000..803b7dcdb --- /dev/null +++ b/doc/plugins/contrib/attach/discussion.mdwn @@ -0,0 +1,18 @@ +I found this posted to todo list, moved here: --[[Joey]] + +> First pass at an attachments plugin. See [[plugins/contrib/attach]] for +> details/docs. Here's the [diff](http://pastebin.com/f4d889b65), and +> here's some [technical notes](http://pastebin.com/f584b9d9d). There are +> still various things I want to fix and tweak, but it works reasonably for +> me as is. + +I guess I missed this when the plugin page was posted last September, and +since the [[soc]] stuff wasn't updated, I didn't realize this was Ben's soc +work. Which is more or less why I didn't look at it. + +This plugin would need quite a lot of work to finish up, I do think it was +taking the right approach, sorry I never followed up on it. + +In the meantime, I've written an attachment plugin that does most of the +same stuff, and behaves closer to how I originally sketched [[todo/fileupload]] +as working. diff --git a/doc/plugins/toggle.mdwn b/doc/plugins/toggle.mdwn index cb76d0b7b..b33575824 100644 --- a/doc/plugins/toggle.mdwn +++ b/doc/plugins/toggle.mdwn @@ -28,3 +28,6 @@ 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. diff --git a/doc/soc.mdwn b/doc/soc.mdwn index c762d2e43..fffb5bed4 100644 --- a/doc/soc.mdwn +++ b/doc/soc.mdwn @@ -11,7 +11,7 @@ accepted, and the following projects were worked on: (See [[todo/latex]]) * Implement File Upload Functionality and Image Gallery Creation by Ben Coffey - (See [[todo/fileupload/soc-proposal]]) + (See [[todo/fileupload/soc-proposal]] and [[plugins/contrib/attach]]) * Wiki WYSIWYG Editor by [[TaylorKillian]] (See [[todo/wikiwyg]]) diff --git a/doc/todo/attachments.mdwn b/doc/todo/attachments.mdwn new file mode 100644 index 000000000..08052f368 --- /dev/null +++ b/doc/todo/attachments.mdwn @@ -0,0 +1,16 @@ +Stuff the [[plugins/attachment]] plugin is currently missing, that might be +nice to add: + +* `mimetype()` pagespecs. (Using a mime type sniffer.) +* Virus scanning. +* Add a progress bar for attachment uploads (needs AJAX stuff..) +* Maybe optimise the "Insert Links" button with javascript, so, if + javascript is available, the link is inserted at the current cursor + position in the page edit form, without actually reposting the form. + (Falling back to the current reposting of the form if javascript is not + available of course.) +* Set `$CGI::POST_MAX` to some sane value (ie, larger than the largest + configured `maxsize()` in the pagespec, or if none is configured, + something reasonable. Just as a belt-and-suspenders DOS prevention. +* Only allow attachments to be added to a given list of pages. + Maybe a pagespec like `parent(patches/*)` diff --git a/doc/todo/attachments_plugin.mdwn b/doc/todo/attachments_plugin.mdwn deleted file mode 100644 index 3b050b43e..000000000 --- a/doc/todo/attachments_plugin.mdwn +++ /dev/null @@ -1 +0,0 @@ -First pass at an attachments plugin. See [[plugins/contrib/attach]] for details/docs. Here's the [diff](http://pastebin.com/f4d889b65), and here's some [technical notes](http://pastebin.com/f584b9d9d). There are still various things I want to fix and tweak, but it works reasonably for me as is.
\ No newline at end of file diff --git a/doc/todo/fileupload.mdwn b/doc/todo/fileupload.mdwn index 1962d6b40..9a9106229 100644 --- a/doc/todo/fileupload.mdwn +++ b/doc/todo/fileupload.mdwn @@ -60,4 +60,4 @@ pagespec lock like the above prevents an edit or upload from happening, ikiwiki could display a reasonable message to the user, indicating what they've done wrong.) -[[tag soc]] +[[tag soc done]] diff --git a/doc/todo/toggle_initial_state.mdwn b/doc/todo/toggle_initial_state.mdwn index f54d33c04..cbbf7e6fd 100644 --- a/doc/todo/toggle_initial_state.mdwn +++ b/doc/todo/toggle_initial_state.mdwn @@ -2,3 +2,5 @@ It would be nice if one could set the initial state of the toggleable area. --[[[rdennis]] [[tag plugins/toggle]] + +[[done]] diff --git a/templates/editpage.tmpl b/templates/editpage.tmpl index b0bb0ecb9..f8eda1b47 100644 --- a/templates/editpage.tmpl +++ b/templates/editpage.tmpl @@ -1,3 +1,4 @@ +<TMPL_VAR JAVASCRIPT> <TMPL_IF NAME="PAGE_CONFLICT"> <p> <b>Your changes conflict with other changes made to the page.</b> @@ -60,6 +61,20 @@ Optional comment about this change:<br /> </TMPL_IF> <TMPL_VAR FORM-SUBMIT> <TMPL_VAR HELPONFORMATTINGLINK> +<a class="toggle" href="#attachments">Attachments</a> +<TMPL_IF NAME="FIELD-ATTACHMENT"> +<div class="<TMPL_VAR ATTACHMENTS-CLASS>" id="attachments"> +<table> +<tr><td colspan="5"><TMPL_VAR FIELD-ATTACHMENT><TMPL_VAR FIELD-UPLOAD></td></tr> +<TMPL_LOOP NAME="ATTACHMENT_LIST"> +<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> +</TMPL_IF> +</table> +</div> +</TMPL_IF> <TMPL_VAR FORM-END> <TMPL_IF NAME="PAGE_PREVIEW"> |