4.7. UseModWiki 补丁

4.7.1. UseModWiki Bug 修正
4.7.2. UseModWiki 功能扩展

在开始撰写本文档时,UseModWiki 的发布版本是 0.92 版,下面的内容有些是针对 0.92 版的,1.0 版本已经修正,因此请对号入座。

4.7.1. UseModWiki Bug 修正

BUG 修正:

  • 修正在 FreeLinks 中使用内部链接的显示错误

    适用于 1.0 版本。参见:http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/AnchorsInFreeLinkBugFix

    如果在 FreeLinks 中使用了 Anchor,即页面内部链接,显示不正常。例如:如下代码

    * [[WikiPatches/AnchorsInFreeLinkBugFix#bottom|Goto bottom]]
    * [[WikiPatches/AnchorsInFreeLinkBugFix#bottom]]
    

    在 1.0 版本的Wiki中显示为

    * [[WikiPatches/AnchorsInFreeLinkBugFix#bottom|Goto bottom]]
    * [[WikiPatches/AnchorsInFreeLinkBugFix#bottom]]
    

    如果应用了如下修正,则能正常显示:

    Goto bottom
    WikiPatches/AnchorsInFreeLinkBugFix#bottom
    

    修正如下:

    
    --- wiki.pl	2003-09-11 20:21:02.000000000 +0800
    +++ wiki.pl.freelink	2003-11-16 22:36:36.468750000 +0800
    @@ -301,9 +301,17 @@
           $AnyLetter = "[-,.()' _0-9A-Za-z]";
         }
       }
    -  $FreeLinkPattern = "($AnyLetter+)";
    +  $FreeLinkPattern = "($AnyLetter+";
       if ($UseSubpage) {
    -    $FreeLinkPattern = "((?:(?:$AnyLetter+)?\\/)?$AnyLetter+)";
    +    $FreeLinkPattern = "((?:(?:$AnyLetter+)?\\/)?$AnyLetter+";
    +  }
    +  if ($NamedAnchors)
    +  {
    +    $FreeLinkPattern .= "(?:#(?:\\w+))?)";
    +  }
    +  else
    +  {
    +    $FreeLinkPattern .= ")";
       }
       $FreeLinkPattern .= $QDelim;
       # Url-style links are delimited by one of:
    @@ -1157,6 +1165,7 @@
     sub GetPageOrEditAnchoredLink {
       my ($id, $anchor, $name) = @_;
       my (@temp, $exists);
    +  my $NamedFreeLink = 0;
     
       if ($name eq "") {
         $name = $id;
    @@ -1164,6 +1173,10 @@
           $name =~ s/_/ /g;
         }
       }
    +  else
    +  {
    +    $NamedFreeLink = 1;
    +  }
       $id =~ s|^/|$MainPage/|;
       if ($FreeLinks) {
         $id = &FreeToNormal($id);
    @@ -1179,7 +1192,7 @@
       }
       if ($exists) {
         $id = "$id#$anchor"  if $anchor;
    -    $name = "$name#$anchor"  if $anchor && $NamedAnchors != 2;
    +    $name = "$name#$anchor"  if $anchor && $NamedAnchors != 2 && !$NamedFreeLink;
         return &GetPageLinkText($id, $name);
       }
       if ($FreeLinks && !$EditNameLink) {
    @@ -1196,7 +1209,8 @@
     
     sub GetPageOrEditLink {
         my ($id, $name) = @_;
    -    return &GetPageOrEditAnchoredLink($id, "", $name);
    +    my ($link, $anchor) = split( /#/, $id, 2);
    +    return &GetPageOrEditAnchoredLink($link, $anchor, $name);
     }
     
     sub GetBackLinksSearchLink {
    
    
  • 使用编号作为目录索引的链接名称

    适用于 1.0 版本。参见:http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/UseNamedAnchorInTOC

    上面介绍过,可以使用如下方式为文章建立索引和带编号的标题。

    
    <toc>
    
    == # heading1 ==
    ...
    
    === # heading2 ===
    ...
    
    ==== # heading3 ====
    ...
    
    

    建立好的目录索引可以跳转到相应的文内链接。建立文内链接的方法是提取相应标题中英文字母进行组合。这就产生了一个问题,如果是相同内容的标题,则会造成重复的文内链接,对于中英文混合的标题,这个内容更加严重。通过应用下面的这个补丁,强制使用数字编号作为目录索引指向的文内链接的名称。

    
    --- wiki.pl	2003-09-11 20:21:02.000000000 +0800
    +++ wiki.pl.numanchor	2003-11-16 22:37:38.515625000 +0800
    @@ -53,7 +53,7 @@
       @IsbnNames @IsbnPre @IsbnPost $EmailFile $FavIcon $RssDays $UserHeader
       $UserBody $StartUID $ParseParas $AuthorFooter $UseUpload $AllUpload
       $UploadDir $UploadUrl $LimitFileUrl $MaintTrimRc $SearchButton 
    -  $EditNameLink $UseMetaWiki @ImageSites $BracketImg );
    +  $EditNameLink $UseMetaWiki @ImageSites $UseNumberedAnchor);
     # Note: $NotifyDefault is kept because it was a config variable in 0.90
     # Other global variables:
     use vars qw(%Page %Section %Text %InterSite %SaveUrl %SaveNumUrl
    @@ -175,6 +175,8 @@
     $EditNameLink = 0;      # 1 = edit links use name (CSS), 0 = '?' links
     $UseMetaWiki  = 0;      # 1 = add MetaWiki search links, 0 = no MW links
     $BracketImg   = 1;      # 1 = [url url.gif] becomes image link, 0 = no img
    +$UseNumberedAnchor = 1;	# 1 = use numbered anchor in NumberedHeadings, 
    +			# 0 = cook anchor by canonicalizing text
     
     # Names of sites.  (The first entry is used for the number link.)
     @IsbnNames = ('bn.com', 'amazon.com', 'search');
    @@ -2116,12 +2118,15 @@
         $text =~ s/\<a\s[^\>]*?\>\?\<\/a\>//si; # No such page syntax
         $text =~ s/\<a\s[^\>]*?\>(.*?)\<\/a\>/$1/si;
         # Cook anchor by canonicalizing $text.
    -    $anchor = $text;
    -    $anchor =~ s/\<.*?\>//g; 
    -    $anchor =~ s/\W/_/g;   
    -    $anchor =~ s/__+/_/g;
    -    $anchor =~ s/^_//;
    -    $anchor =~ s/_$//;
    +    if (!$UseNumberedAnchor)
    +    {
    +        $anchor = $text;
    +        $anchor =~ s/\<.*?\>//g; 
    +        $anchor =~ s/\W/_/g;   
    +        $anchor =~ s/__+/_/g;
    +        $anchor =~ s/^_//;
    +        $anchor =~ s/_$//;
    +    }
         # Last ditch effort
         $anchor = '_' . (join '_', @HeadingNumbers) unless $anchor;
         $TableOfContents .= $number . &ScriptLink("$OpenPageName#$anchor",$text)
    
    
  • 禁止页面缓存

    [注意]

    适用于 0.92 版,1.0 可以参照进行类似修改。

    页面缓存会引起网页浏览者不能及时看到更新的网页。在 http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/PageCacheBugFix 上面有一个补丁。

    
    --- usemod092/wiki.pl   Sun Apr 22 00:44:10 2001
    +++ wiki.cgi    Sun Apr 29 00:01:57 2001
    @@ -973,6 +973,8 @@
     sub GetHttpHeader {
       my $cookie;
    +  my $now;
    +  $now = gmtime;
       if (defined($SetCookie{'id'})) {
         $cookie = "$CookieName="
                 . "rev&" . $SetCookie{'rev'}
    @@ -981,12 +983,20 @@
         $cookie .= ";expires=Fri, 08-Sep-2010 19:48:23 GMT";
         if ($HttpCharset ne '') {
           return $q->header(-cookie=>$cookie,
    +                        -pragma=>"no-cache",
    +                        -cache_control=>"no-cache",
    +                        -last_modified=>"$now",
    +                        -expires=>"+10s",
                             -type=>"text/html; charset=$HttpCharset");
         }
         return $q->header(-cookie=>$cookie);
       }
       if ($HttpCharset ne '') {
    -    return $q->header(-type=>"text/html; charset=$HttpCharset");
    +    return $q->header(-type=>"text/html; charset=$HttpCharset",
    +                      -pragma=>"no-cache",
    +                      -cache_control=>"no-cache",
    +                      -last_modified=>"$now",
    +                      -expires=>"+10s");
       }
       return $q->header();
     }
    
    
  • 解决 $ThinLine 和 $UseHeadings 引起的冲突

    [注意]

    适用于 0.92 版,1.0 可以参照进行类似修改。

    如下的解决方案来自:http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/ThinLineHeadingsConflict。更严格的匹配 ==== ,避免了误将第四级的标题处理成为两条水平线。

    
    --- usemod092/wiki.pl
    +++ wiki.cgi    
    @@ -1223,7 +1233,7 @@
         s/$ISBNPattern/&StoreISBN($1)/geo;
         if ($ThinLine) {
           s/----+/<hr noshade size=1>/g;
    -      s/====+/<hr noshade size=2>/g;
    +      s/^\s*====+\s*$/<hr noshade size=2>/gmx;
         } else {
           s/----+/<hr>/g;
         }
    
    

    有另外一种解决方案,即用减号"-"的多少来决定分隔线的粗细,而不是用易于混淆的等号。

    
    --- usemod092/wiki.pl
    +++ wiki.cgi    
    @@ -1222,8 +1222,11 @@
         s/$RFCPattern/&StoreRFC($1)/geo;
         s/$ISBNPattern/&StoreISBN($1)/geo;
         if ($ThinLine) {
    -      s/----+/<hr noshade size=1>/g;
    -      s/====+/<hr noshade size=2>/g;
    +      s/--------+/<hr noshade style="height:5px">/g;
    +      s/-------+/<hr noshade style="height:4px">/g;
    +      s/------+/<hr noshade style="height:3px">/g;
    +      s/-----+/<hr noshade style="height:2px">/g;
    +      s/----+/<hr noshade style="height:1px">/g;
         } else {
           s/----+/<hr>/g;
         }
    
    
  • 引用相对 URL 的补丁

    [注意]

    适用于 0.92 版,1.0 已支持。

    UseModWiki 0.92 版本处理文本中的 URL 有一个缺陷。即没法使用相对或者决定路径来引用本网站的内容,如果需要引用本网站的内容,也必须把 URL 写成如:http://foobar.worldhello.net/images/usemod.gif。这是多么的不方便,而且如果网站名称修改,那么文中的链接就都出错了。UseMod 网站上有一个补丁可以解决这个问题,即允许通过写 URL片断(非正规URL格式)达到引用本网站链接的目的:http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/PartialUrlFix

    修改如下:

    *** usemod092/wiki.pl	Sat Apr 21 17:44:10 2001
    --- wiki.pl	Fri Jan 18 11:36:25 2002
    ***************
    *** 1417,1422 ****
    --- 1417,1423 ----
        }
        # Restricted image URLs so that mailto:foo@bar.gif is not an image
        if ($useImage && ($name =~ /^(http:|https:|ftp:).+\.$ImageExtensions$/)) {
    +     $name = $1 if ($name =~ /^https?:(.*)/ && $1 !~ /^\/\//); 1
          return ("<img src=\"$name\">", $punct);
        }
        return ("<a href=\"$name\">$name</a>", $punct);
    ***************
    *** 1425,1430 ****
    --- 1426,1432 ----
      sub StoreBracketUrl {
        my ($url, $text) = @_;
      
    +   $url = $1 if ($url =~ /^https?:(.*)/ && $1 !~ /^\/\//); 2
        if ($text eq "") {
          $text = &GetBracketUrlIndex($url);
        }
    
    1

    对于形如 http:/images/usemod.gif 的非正规 URL,如果不加修正,返回 <img src="http:/images/usemod.gif">,这是不正确的。对于此情况,将 $name 修改为: "/images/usemod.gif",返回的链接为 <img src="/images/usemod.gif"> 是正确的。

    2

    同上

4.7.2. UseModWiki 功能扩展

功能扩展

  • 添加支持表格语法的功能

    [注意]

    适用于 0.92 版,1.0 已支持。

    当一行以双竖线"||"开始,表示开始绘制表格的语法,例如:

    ||align=center border=1 width=50%
    ||居左    ||  居中  ||    居右||
    ||  测试  ||    测试||测试    ||
    ||||  跨越多栏      ||    测试||
    

    将显示如下:

    Wiki 绘制表格

    Wiki 绘制表格

    其补丁可以在 http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/TableSyntax 上找到。这个页面上可以看到许多开发者对这个功能的补充,充分展示了 Wiki 的协作精神。

    --- wiki_92.pl
    +++ wiki.pl
    @@ -45,7 +45,7 @@
       $UrlProtocols $UrlPattern $ImageExtensions $RFCPattern $ISBNPattern
       $FS $FS1 $FS2 $FS3 $CookieName $SiteBase $StyleSheet $NotFoundPg
       $FooterNote $EditNote $MaxPost $NewText $NotifyDefault $HttpCharset
    -  $UserGotoBar);
    +  $UserGotoBar $TableMode $TableSyntax); 1
     # Note: $NotifyDefault is kept because it was a config variable in 0.90
     # Other global variables:
     use vars qw(%Page %Section %Text %InterSite %SaveUrl %SaveNumUrl
    @@ -98,6 +98,7 @@
     $RunCGI      = 1;       # 1 = Run script as CGI,  0 = Load but do not run
     $EmailNotify = 0;       # 1 = use email notices,  0 = no email on changes
     $EmbedWiki   = 0;       # 1 = no headers/footers, 0 = normal wiki pages
    +$TableSyntax = 1;       # 1 = wiki syntax tables, 0 = no magic table syntax 2
     
     # Minor options:
     $LogoLeft    = 0;       # 1 = logo on left,       0 = logo on right
    @@ -1152,6 +1153,7 @@
     # ==== Common wiki markup ====
     sub WikiToHTML {
       my ($pageText) = @_;
    +  $TableMode = 0; #PATCH
     
       %SaveUrl = ();
       %SaveNumUrl = ();
    @@ -1236,18 +1238,29 @@
         if ($UseHeadings) {
           s/(^|\n)\s*(\=+)\s+([^\n]+)\s+\=+/&WikiHeading($1, $2, $3)/geo;
         }
    +    if ($TableMode) {
    +      while (/(\|\|)+([^\|<]+)/) {
    +        my $align = $2;
    +        $align = $align =~/^  / ? ($align =~/  $/ ? 'CENTER' : 'RIGHT') : ($align =~/  $/ ? 'LEFT' : 'CENTER'); 3
    +        s/((\|\|)+)/"<\/TD><TD ALIGN='$align' COLSPAN=\"" . (length($1)\/2) . "\">"/e;
    +      }
    +    }
       }
       return $_;
     }
     
     sub WikiLinesToHtml {
       my ($pageText) = @_;
    -  my ($pageHtml, @htmlStack, $code, $depth, $oldCode);
    +  my ($pageHtml, @htmlStack, $code, $codeAttributes, $depth, $oldCode); #PATCH
    +
     
       @htmlStack = ();
       $depth = 0;
       $pageHtml = "";
    -  foreach (split(/\n/, $pageText)) {  # Process lines one-at-a-time
    +  $codeAttributes = '';  4
    +  foreach (split(/\r?\n/, $pageText)) {  # Process lines one-at-a-time
    +    $code = '';           #PATCH
    +    $TableMode = 0;
         $_ .= "\n";
         if (s/^(\;+)([^:]+\:?)\:/<dt>$2<dd>/) {
           $code = "DL";
    @@ -1261,12 +1274,25 @@
         } elsif (s/^(\#+)/<li>/) {
           $code = "OL";
           $depth = length $1;
    +    } elsif ($TableSyntax && s/^\|\|\s*(.*[^\|])\n\z//) {   5
    +      $TableMode = 1;
    +      $codeAttributes = $1;
    +    } elsif ($TableSyntax && /^(\|\|)+.*\|\|\s*$/) { 6
    +      /^(\|\|)+([^\|]+)/;
    +      my $align = $2;
    +      $align =  $align =~/^  / ? ($align =~/  $/ ? 'CENTER' : 'RIGHT') : ($align =~/  $/ ? 'LEFT' : 'CENTER');
    +      s/^((\|\|)+)(.*)\|\|\s*$/"<TR VALIGN='CENTER'><TD ALIGN='$align' COLSPAN='" . (length($1)\/2) . "'>$3<\/TD><\/TR>\n"/e;
    +      $code = "TABLE";
    +      $codeAttributes ||= "BORDER=\"1\"";
    +      $TableMode = 1;
    +      $depth = 1;
         } elsif (/^[ \t].*\S/) {
           $code = "PRE";
           $depth = 1;
         } else {
           $depth = 0;
         }
    +    $codeAttributes = '' unless $TableMode;
         while (@htmlStack > $depth) {   # Close tags as needed
           $pageHtml .=  "</" . pop(@htmlStack) . ">\n";
         }
    @@ -1281,7 +1307,7 @@
           }
           while (@htmlStack < $depth) {
             push(@htmlStack, $code);
    -        $pageHtml .= "<$code>\n";
    +        $pageHtml .= "<$code $codeAttributes>\n"; #PATCH
           }
         }
         s/^\s*$/<p>\n/;                        # Blank lines become <p> tags
    
    1

    添加全局变量:$TableMode, $TableSyntax

    2

    打开表格语法功能的开关

    3

    根据包含在两个双竖线"||"中文字的左右是否包含空格,确定一个表格单元格中文字的对齐方式。对于 "||居左 ||" 设置为居左,"|| 居中 ||" 设置为居中,"|| 居右||" 设置为居右。

    4

    $codeAttributes 将保存整个表格的格式信息

    5

    匹配表格属性行,设置表格格式信息 $codeAttributes。例如匹配:“||align=center border=1 width=50%”。

    6

    匹配表格内容描述行,将内容转换为对应的 HTML 表格。例如匹配:“||居左 || 居中 || 居右||”。

  • TaviStyleHistory

    [注意]

    适用于 0.92 版,1.0 已支持。

    Taiv 是以 PHP 实现的另一种著名的 WikiClone,其版本比较的界面功能比较强,可以选择某两个版本进行比较,它的功能已经被移植到 UseModWiki。参见:

    http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/TaviStyleHistory

  • 为管理员添加工具箱

    [注意]

    适用于 0.92 版,1.0 已支持。

    当用户以管理员身份登录后,在页面的最低端,显示出管理功能的链接。代码参见:http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/GetAdminBar

  • 删除页面功能

    [注意]

    适用于 0.92 版,1.0 已支持。

    UseModWiki 的管理员可以通过 action=editlinks 删除页面,而普通用户则不能。下面的这个功能扩展,允许用户将页面的第一行插入 "DeletedPage",将页面标记为待删除,在下次系统维护时,将标记为删除且过期的页面删除。参见: http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/PageDeletion

    *** usemod092/wiki.pl	Sat Apr 21 17:44:10 2001
    --- wiki.pl
    @@ -45,7 +45,7 @@
       $UrlProtocols $UrlPattern $ImageExtensions $RFCPattern $ISBNPattern
       $FS $FS1 $FS2 $FS3 $CookieName $SiteBase $StyleSheet $NotFoundPg
       $FooterNote $EditNote $MaxPost $NewText $NotifyDefault $HttpCharset
    -  $UserGotoBar);
    +  $UserGotoBar $DeletedPage);
     # Note: $NotifyDefault is kept because it was a config variable in 0.90
     # Other global variables:
     use vars qw(%Page %Section %Text %InterSite %SaveUrl %SaveNumUrl
    @@ -98,6 +98,7 @@
     $RunCGI      = 1;       # 1 = Run script as CGI,  0 = Load but do not run
     $EmailNotify = 0;       # 1 = use email notices,  0 = no email on changes
     $EmbedWiki   = 0;       # 1 = no headers/footers, 0 = normal wiki pages
    +$DeletedPage = "DeletedPage";   # 0 = disable page deletion; "string" for page  deletion marker text
     
     # Minor options:
     $LogoLeft    = 0;       # 1 = logo on left,       0 = logo on right
    @@ -3497,6 +3558,28 @@
       close(OUT);
     }
     
    +# Actions are vetoable if someone edits the page before
    +# the keep expiry time. For example, page deletion. If
    +# no one edits the page by the time the keep expiry time
    +# elapses, then no one has vetoed the last action, and the
    +# action is accepted.
    +# See http://www.usemod.com/cgi-bin/mb.pl?PageDeletion
    +#
    +# returns ' (deleted)' if the page has been deleted, 0 otherwise.
    +sub ProcessVetos {
    +  my ($expirets);
    +  $expirets = $Now - ($KeepDays * 24 * 60 * 60);
    +  return 0 unless $Page{'ts'} < $expirets;  1
    +
    +  if( $DeletedPage && $Text{'text'} =~ /^\s*$DeletedPage\W*?(\n|$)/o ) 2
    +  {
    +    &DeletePage($OpenPageName, 1, 1);
    +    return ' (deleted)'; 3
    +  }
    +
    +  return 0;
    +}
    +
     sub DoMaintain {
       my ($name, $fname, $data);
       print &GetHeader('', T('Maintenance on all pages'), '');
    @@ -3515,9 +3598,11 @@
       foreach $name (&AllPagesList()) {
         &OpenPage($name);
         &OpenDefaultText();
    -    &ExpireKeepFile();
    +    my $message = &ProcessVetos();
    +    &ExpireKeepFile() unless $message eq ' (deleted)';
         print ".... "  if ($name =~ m|/|);
    -    print &GetPageLink($name), "<br>\n";
    +    print &GetPageLink($name);
    +    print "$message<br>\n";
       }
       &WriteStringToFile($fname, "Maintenance done at " . &TimeToText($Now));
       &ReleaseLock();
    ]]>
    
    1

    如果文件没有过期,不进行下面的判断。

    2

    仅在文件的第一行进行匹配,$DeletedPage 前面可以有空格,后面可以有任意非单词字符([^_0-9a-zA-Z]),符合这样的规则的文件标记为删除。

    3

    返回的文字,将显示在维护页面上。

  • BetterEditPage

    [注意]

    适用于 0.92 版,1.0 可以参照进行类似修改。

    在编辑页面加入语法提示,对 Wiki 新手非常有帮助。参见:

    http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/BetterEditPage

  • 定制导航条

    [注意]

    适用于 0.92 版,1.0 可以参照进行类似修改。

    在导航条添加新的选项,如 Login(登录), Index(页面索引),亦即调用 "action=login" 和 "action=index"。参见:

    http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/Login

    http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/Index

  • SaveButtonAtBottomOfPreview

    [注意]

    适用于 0.92 版,1.0 可以参照进行类似修改。

    在预览之后加上保存的按钮,不用再将窗口滚动到上面来保存内容。参见:

    http://www.usemod.com/cgi-bin/wiki.pl?WikiPatches/SaveButtonAtBottomOfPreview

  • 添加样式表支持

    [注意]

    适用于 0.92 版,1.0 已支持。

    参照如下网址,修改 wiki.pl,使生成的页面支持样式表。

    http://www.usemod.com/cgi-bin/wiki.pl?WikiWithCascadingStyleSheet/CSSClasses

    写一个相应的样式表。UseModWiki 网站上有示例:http://www.usemod.com/cgi-bin/wiki.pl?WikiWithCascadingStyleSheet/WikiStyleSheet

    设置 config 配置文件中的 $StyleSheet,使之指向我们定制好的样式表文件,示例如下:

    $StyleSheet  = "/inc/css/usemodwiki.css";
    
  • 设置网页编辑确省发送邮件

    [注意]

    适用于 1.0 版本。

    网页编译中的发送邮件选项确省关闭,如果想要修改该确省值,参照如下方式修改:

    
      if ($EmailNotify) {
        print "&nbsp;&nbsp;&nbsp;" .
    -           $q->checkbox(-name=> 'do_email_notify',
    +           $q->checkbox(-name=> 'do_email_notify', -checked=>1,
          -label=>Ts('Send email notification that %s has been changed.', $id));
      }
    
    

更多的 UseModWiki 功能扩充参见:http://www.usemod.com/cgi-bin/wiki.pl?WikiSuggestions