[첫화면으로]UseModWiki소스수정/기능추가및개선

마지막으로 [b]

38 번째 수정본
1. 기능 추가 또는 개선
1.1. 데이타 디렉토리와 설정 화일 위치 변경 (optional)
1.2. Index 의 페이지 목록을 제목의 첫글자별로 구분
1.3. 상단 메뉴바에 사용자 정의 링크 추가 (optional)
1.4. 외부 URL 옆에 "새 창으로 열기" 아이콘 표시 (optional)
1.5. 상단 메뉴에 상위페이지 아이콘 표시 (optional)
1.6. {{{ }}} 태그 추가
1.7. 이모티콘 도움말 추가
1.8. UseModWiki번역화일 사용
1.9. 페이지 목록에서 잠겨 있는 페이지 표시
1.10. 페이지 하단에 수정금지 여부와 설정/해제 표시 (optional)
1.11. 이미지에 마우스를 갖다 대면 URL 보임 (optional)
1.12. 편집을 취소하고 원래 페이지로 돌아가는 링크 추가
1.13. 페이지 수정 불가 메시지에, 사이트 제목 대신 페이지명이 나오도록 수정 (optional)
1.14. 탐색을 편하게 하기 위한 단축키 추가 (optional)
1.14.1. 검색란에 Alt+S 단축키 할당
1.14.2. 사이트 로고 이미지에 Alt+W 할당
1.14.3. 페이지 상단에 Alt+Z 할당
1.14.4. 페이지 하단에 Alt+X 할당
1.14.5. 텍스트 편집영역에 Alt+I 할당
1.15. 페이지 수정하기로 들어갔을 때 커서가 편집 영역에 놓이게 함
1.16. 로그인 화면에서 커서가 아이디 입력 필드에 놓이게 함
1.17. 페이지 정보 출력 양식 변경
1.18. {{{ }}} 태그 개선 및 SyntaxHighlighting 지원
1.19. 페이지를 저장할 때 수행되는 매크로 도입
1.19.1. <mysign> 매크로 도입
1.20. <mysign(name,time)> 매크로 도입
1.21. <include> 매크로 출력을 html 변환
1.22. 테이블 정렬 방식 개선 및 rowspan 기능 추가
1.23. <calendar> 매크로 추가
1.24. <wikiversion> 매크로 추가 (optional)
1.25. <vote(count[,scale])> 매크로 추가
1.26. 존재하지 않는 페이지의 링크를 WikiX 스타일로 출력
1.27. GetFullLinkList 함수에 파라메터 사용을 가능하게 함
1.28. 페이지 제목을 클릭했을때 진정한 의미의 역링크 출력
1.29. RemoveLink() 함수 추가
1.30. allpagesto 매크로 추가
1.31. allpagesfrom 매크로 추가
1.32. orphanedpages 매크로 추가
1.33. wantedpages 매크로 추가
1.34. includenotoc 매크로 추가
1.35. #EXTERN 명령어 추가
1.36. InterWiki 로 된 이미지 화일 처리
1.37. mms 프로토콜 인식
1.38. IMG: 태그 개선
1.39. 존재하지 않는 페이지의 링크 스타일을 사용자가 결정할 수 있게 함
1.40. userlist 매크로 추가
1.41. titleindex action 추가
1.42. form 을 생성할 때 form 의 이름을 부여할 수 있도록 함

1. 기능 추가 또는 개선

1.1. 데이타 디렉토리와 설정 화일 위치 변경 (optional)

# == Configuration =====================================================
# $DataDir     = "data"; # Main wiki directory
# 자기가 사용할 데이타 디렉토리와 설정화일명을 아래에 적어준다
$DataDir     = "newdata";      # Main wiki directory
$ConfigFile  = "newconfig.pl"; # path of config file

sub DoWikiRequest {
#   if 구문을 다음과 같이 고친다
#   if ($UseConfig && (-f "config.pl")) {
#       do "config.pl";  # Later consider error checking?
#   }
    if ($UseConfig && (-f $ConfigFile)) {
        do "$ConfigFile";
    }
    ...
}

1.2. Index 의 페이지 목록을 제목의 첫글자별로 구분

# 다음의 함수를 통채로 바꿈
sub PrintPageList {
        my ($pagename);
        my $count = 0;
        my $titleIsPrinted = 0;
        my @han = qw(가 나 다 라 마 바 사 아 자 차 카 타 파 하);
        my @indexTitle = (0, "A".."Z");
        push (@indexTitle, @han, "기타");
        my @indexSearch=("A".."Z");
        push (@indexSearch, @han, "豈");

        print "<h2>", Ts('페이지 수: %s', ($#_ + 1)), "</h2>\n";

        my $count2 = 0;
        print("\n|");
        while ( $count2 <= $#indexTitle ) {
                if ($count2 == 27) {
                        print("<br>\n|");
                }
                print("<a href=\"#H_$indexTitle[$count2]\"><b>");
                print("&nbsp;$indexTitle[$count2]&nbsp;");
                print("</b></a>|");
                $count2++;
        }
        print "<br><br>";
        $count2 = 0;

        foreach $pagename(@_) {
                until (
                        $pagename lt @indexSearch[$count]
                        && ($count == 0 || $pagename gt @indexSearch[$count-1])
                ) {
                        $count++;
                        $titleIsPrinted = 0;
                        last if $count > 40;
                }
                if (!$titleIsPrinted) {
                        while ( $count2 <= ($count - 1) ) {
                                print "\n<a name=\"H_$indexTitle[$count2]\">";
                                print "</a>";
                                $count2++;
                        }
                        print "\n<a name=\"H_$indexTitle[$count]\">";
                        print $q->h3($indexTitle[$count]);
                        print "</a>";
                        $count2 = $count + 1;
                        $titleIsPrinted=1;
                }

                print ".... " if ($pagename =~ m|/|);
                print &GetPageLink($pagename);

                if (&UserIsAdmin()) {
                        print " | " . &ScriptLink("action=pagelock&set=1&id=" .$pagename, T('lock'));
                        print " | " . &ScriptLink("action=pagelock&set=0&id=" .$pagename, T('unlock'));
                }
                print $q->br;
                print "\n";
        }
}

1.3. 상단 메뉴바에 사용자 정의 링크 추가 (optional)

### 제일 끝에 UserGotoBar2~4 추가
use vars qw(@RcDays @HtmlPairs @HtmlSingle
        $TempDir $LockDir $DataDir $HtmlDir $UserDir $KeepDir $PageDir
        ...
        $UserGotoBar $UserGotoBar2 $UserGotoBar3 $UserGotoBar4);
...
sub GetGotoBar {
        ...
        $bartext .= ' </td><td> ' . &GetSearchForm();
        if ($UserGotoBar ne '') {
                $bartext .= " </td><td> " . $UserGotoBar;
        }
### 다음 단락을 추가. UserGotoBar3 와 4 도 원하는 위치에 삽입하면 됨
        if ($UserGotoBar2 ne '') {
                $bartext .= " </td><td> " . $UserGotoBar2;
        }
### 여기까지
        $bartext .= "</td></tr>";
        $bartext .= $q->endform;
        $bartext .= "</table><hr>\n";
        return $bartext;
}
...

1.4. 외부 URL 옆에 "새 창으로 열기" 아이콘 표시 (optional)

sub InterPageLink {
        ...
#       return ("<a href=\"$url\">$name</a>", $punct);
        return ("<a href=\"$url\">$name</a><a href=\"$url\" target=\"_blank\"><img src=\"아이콘경로\" border=\"0\" alt=\"새 창으로 열기\" align=\" absbottom\"></a>", $punct);
}
sub StoreBracketInterPage {
        ...
#       return &StoreRaw("<a href=\"$url\">[$text]</a>");
        return &StoreRaw("<a href=\"$url\">[$text]</a><a href=\"$url\" target=\"_blank\"><img src=\"아이콘경로\" border=\"0\" alt=\"새 창으로 열기\" align=\"absbottom\"></a>");
}

sub UrlLink {
        ...
#       return ("<a href=\"$name\">$name</a>", $punct);
        return ("<a href=\"$name\">$name</a><a href=\"$name\" target=\"_blank\"><img src=\"아이콘경로\" border=\"0\" alt=\"새 창으로 열기\" align=\"absbottom\"></a>", $punct);
}
sub StoreBracketUrl {
        ...
#       return &StoreRaw("<a href=\"$url\">[$text]</a>");
        return &StoreRaw("<a href=\"$url\">[$text]</a><a href=\"$url\" target=\"_blank\"><img src=\"아이콘경로\" border=\"0\" alt=\"새 창으로 열기\" align=\"absbottom\"></a>");
}

1.5. 상단 메뉴에 상위페이지 아이콘 표시 (optional)

...
sub GetGotoBar {
        ...
        if ($id =~ m|/|) {
                $main = $id;
                $main =~ s|/.*||;  # Only the main page name (remove subpage)
#               $bartext .= " </td><td> " . &GetPageLink($main);        이 줄을 아래와 같이 바꾼다
                $bartext .= " </td><td> <img src=\"./emoticon/parentpage.gif\" border=\"0\" alt=\"상위페이지: $main\" align=\"absmiddle\">" . &GetPageLink($main);
        }
        ...
}
...

1.6. {{{ }}} 태그 추가

1.7. 이모티콘 도움말 추가

sub DoHelp {
        ...
<goto(바보)>
        |;
        }
### 여기서부터 추가
    elsif ($idx eq 5) {
        if ($UseEmoticon eq 0) {
            $text = q|
'''현재 이 홈페이지에서는 이모티콘을 사용하지 않도록 설정되어 있습니다.'''
'''따라서 아래의 도움말은 적용되지 않습니다.'''
            |;
        }
        $text .= q|
== 이모티콘 ==
이모티콘은 감정표현에 사용되는 작은 그림입니다. <br>
다음과 같은 문자열 중 하나를 입력하시면 왼쪽의 그림이 자동으로 삽입됩니다.

* ^^  <nowiki>^^ ^-^ ^_^ ^o^ ^O^ ^^; ^-^; ^_^; ^o^ ^O^ :-D :D</nowiki>
* :-) <nowiki>:-)</nowiki>
* -_- <nowiki>-_- -_-; =.= =.=; :-s :-S</nowiki>
* o.O <nowiki>o.O *.* :-o :-O :o :O</nowiki>
* :-( <nowiki>:-( :(</nowiki>
* :-p <nowiki>:-p :-P :p :P</nowiki>
* ;-) <nowiki>;-) ;)</nowiki>
    |;
    }
### 여기까지
        $ClickEdit = 0;
        print &GetHttpHeader();
        ...
}
sub DoEdit {
        ...
        print &HelpLink(3, "링크와 이미지") . " | ";

#       print &HelpLink(4, "매크로") . "<br>";       이 줄을 아래 두 줄로 바꿈
        print &HelpLink(4, "매크로") . " | ";
        print &HelpLink(5, "이모티콘") . "<br>";

        print &GetFormStart();
        ...
}

1.8. UseModWiki번역화일 사용

do "./translations/korean.pl";    # 번역 화일의 경로

1.9. 페이지 목록에서 잠겨 있는 페이지 표시

sub PrintPageList {
    ...
        if (&UserIsAdmin()) {
### 아래의 if { } 문 삽입
            if (-f &GetLockedPageFile($pagename)) {
                print " " . T('(locked)');
            }
### 여기까지
            print " | " . &ScriptLink("action=pagelock&set=1&id=" . $pagename, T('lock'));
            print " | " . &ScriptLink("action=pagelock&set=0&id=" . $pagename, T('unlock'));
        }
   ...
}

1.10. 페이지 하단에 수정금지 여부와 설정/해제 표시 (optional)

sub GetEditGuide {
    my ($id, $rev) = @_;
    my $result = "<div align=right>";

### 다음 코드를 삽입.
    if (&UserIsAdmin()) {
        if (-f &GetLockedPageFile($id)) {
            $result .= T('(locked)') . " | ";
        }
        $result .= &ScriptLink("action=pagelock&set=1&id=" . $id, T('lock'));
        $result .= " | " . &ScriptLink("action=pagelock&set=0&id=" . $id, T('unlock'));
        $result .= "<br>";
    }
### 여기까지

    if (&UserCanEdit($id, 0)) {
        if ($rev ne '') {
    ...
}

1.11. 이미지에 마우스를 갖다 대면 URL 보임 (optional)

sub UrlLink {
    ...
    if ($useImage && ($name =~ /^(http:|https:|ftp:).+\.$ImageExtensions$/)) {
        $name = $1 if ($name =~ /^https?:(.*)/ && $1 !~ /^\/\//);
### 다음 라인을 수정
#       return ("<img $ImageTag src=\"$name\">", $punct);
        return ("<img $ImageTag src=\"$name\" alt=\"$name\">", $punct);
###
    }
    ...
}

1.12. 편집을 취소하고 원래 페이지로 돌아가는 링크 추가

sub DoEdit {
    ....
        print "<h2>", T('Preview only, not yet saved'), "</h2>\n";
    }
### 다음 라인을 추가
    print Ts('Return to %s' , &GetPageLink($id)) . " | ";
###
    print &GetHistoryLink($id, T('View other revisions')) . "<br>\n";
    ...
}

1.13. 페이지 수정 불가 메시지에, 사이트 제목 대신 페이지명이 나오도록 수정 (optional)

sub DoEdit {
    ...
    if (!&UserCanEdit($id, 1)) {
        ...
        } else {
### 다음 라인을 수정
#           print Ts('Editing not allowed: %s is read-only.', $SiteName);
            print Ts('Editing not allowed: %s is read-only.', $id);
###
        }
        print &GetCommonFooter();
        return;
    }
    # Consider sending a new user-ID cookie if user does not have one
    ...
}

1.14. 탐색을 편하게 하기 위한 단축키 추가 (optional)

1.14.1. 검색란에 Alt+S 단축키 할당

sub GetSearchForm {
    my ($result);
### 다음 부분을 변경
#   $result = "Search: <input class=text type=text name='search' size=10>"
# . $q->textfield(-name=>'search', -size=>12)
#                       . &GetHiddenValue("dosearch", 1);

    $result = T('Search:') . " <input accesskey=\"s\"class=text type=text name='search' size=10>"
                        . &GetHiddenValue("dosearch", 1);
###
    return $result;
}

1.14.2. 사이트 로고 이미지에 Alt+W 할당

sub GetHeader {
    ...
    if ((!$embed) && ($LogoUrl ne "")) {
        $logoImage = "img src=\"$LogoUrl\" alt=\"$altText\" border=0";
        if (!$LogoLeft) {
            $logoImage .= " align=\"right\"";
        }
### 다음 라인을 아래와 같이 바꾼다
#       $header = &ScriptLink($HomePage, "<$logoImage>");
        $header = "<a accesskey=\"w\" href=\"$ScriptName?$HomePage\"><$logoImage></a>";
###
    }
    if ($id ne '') {
    ...
}

1.14.3. 페이지 상단에 Alt+Z 할당

sub GetHeader {
    ...
        $result .= $q->h1($header . $title);
    }
### 다음 라인 추가
    $result .= "\n<div align=\"right\"><a accesskey=\"z\" name=\"#PAGE_TOP\" href=\"#PAGE_BOTTOM\">". T('Bottom') . "</a></div>\n";
###

    if (&GetParam("toplinkbar", 1)) {
        # Later consider smaller size?
    ...
}

1.14.4. 페이지 하단에 Alt+X 할당

sub GetMinimumFooter {
# 함수의 본문을 통채로 바꾼다.
#   if ($FooterNote ne '') {
#       return T($FooterNote) . $q->end_html;  # Allow local translations
#   }
#   return $q->end_html;

    my $result = '';
    if ($FooterNote ne '') {
        $result .= T($FooterNote);  # Allow local translations
    }
    $result .= "\n<div align=\"right\"><a accesskey=\"x\" name=\"#PAGE_BOTTOM\" href=\"#PAGE_TOP\">" . T('Top') . "</a></div>\n" . $q->end_html;
    return $result;
}

1.14.5. 텍스트 편집영역에 Alt+I 할당

sub GetTextArea {
    my ($name, $text, $rows, $cols) = @_;
### 이건 부등호 처리문제 패치에서 적용한 라인
    $text =~ s/(\&)/\&amp;/g;

### 아래의 두 return 문에 accesskey 값을 추가한다.
#   if (&GetParam("editwide", 1)) {
#       return $q->textarea(-name=>$name, -default=>$text,
#                                               -rows=>$rows, -columns=>$cols, -override=>1,
#                                               -style=>'width:100%', -wrap=>'virtual');
#   }
#   return $q->textarea(-name=>$name, -default=>$text,
#                                           -rows=>$rows, -columns=>$cols, -override=>1,
#                                           -wrap=>'virtual');

    if (&GetParam("editwide", 1)) {
        return $q->textarea(-accesskey=>'i', -name=>$name, -default=>$text,
                                                -rows=>$rows, -columns=>$cols, -override=>1,
                                                -style=>'width:100%', -wrap=>'virtual');
    }
    return $q->textarea(-accesskey=>'i', -name=>$name, -default=>$text,
                                            -rows=>$rows, -columns=>$cols, -override=>1,
                                            -wrap=>'virtual');

###
}

1.15. 페이지 수정하기로 들어갔을 때 커서가 편집 영역에 놓이게 함

sub DoEdit {
    ...
    print &HelpLink(5, "이모티콘") . "<br>\n";
### 다음 라인 교체
#   print &GetFormStart();
    print &GetFormStart("form_edit");                  # 예전 패치에 없던 부분
###
    print &GetHiddenValue("title", $id), "\n",
    ...
    print $q->endform;
### 다음 코드를 추가
    print "\n<script language=\"JavaScript\" type=\"text/javascript\">\n"
        . "<!--\n"
        . "document.form_edit.text.focus();\n"         # 예전 패치에서 재수정
        . "//-->\n"
        . "</script>\n";
### 여기까지
    print &GetMinimumFooter();
}

1.16. 로그인 화면에서 커서가 아이디 입력 필드에 놓이게 함

sub DoEnterLogin {
    print &GetHeader('', T('Login'), "");
### 다음 라인 교체
#   print &GetFormStart();
    print &GetFormStart("form_login");                      # 예전 패치에 없던 부분
###
    print &ScriptLink("action=newlogin", T('Create new UserName') . "<br>");
    ...
    print $q->endform;
### 다음 단락 추가
    print "\n<script language=\"JavaScript\" type=\"text/javascript\">\n"
        . "<!--\n"
        . "document.form_login.p_userid.focus();\n"         # 예전 패치에서 재수정
        . "//-->\n"
        . "</script>\n";
###
    print &GetMinimumFooter();
}

1.17. 페이지 정보 출력 양식 변경

sub GetEditGuide {
    ...
#   if (&UserCanEdit($id, 0)) {    여기서부터
#       if ($rev ne '') {
#   ...
#
#   $result .= "</div>";           여기까지를 다음과 같이 변경

    if ($Section{'revision'} > 0) {
        $result .= '<br>';
        if ($rev eq '') {  # Only for most current rev
            $result .= T('Last edited');
        } else {
            $result .= T('Edited');
        }
        $result .= ' ' . &TimeToText($Section{ts});
    }
    if ($UseDiff) {
        $result .= ' ' . &ScriptLinkDiff(4, $id, T('(diff)'), $rev);
    }

    $result .= '<br>';

    $result .= &GetHistoryLink($id, T('History'));
    if ($rev ne '') {
        $result .= ' | ';
        $result .= &GetPageLinkText($id, T('View current revision'));
    }

    $result .= ' | ';

    if (&UserCanEdit($id, 0)) {
        if ($rev ne '') {
            $result .= &GetOldPageLink('edit',   $id, $rev,
                           Ts('Edit revision %s of this page', $rev));
        } else {
            $result .= &GetEditLink($id, T('Edit text of this page'));
        }
    } else {
        $result .= T('This page is read-only');
    }
    $result .= "</div>";
### 여기까지
    return $result;
}

1.18. {{{ }}} 태그 개선 및 SyntaxHighlighting 지원

sub GetPageLinks {
    ...
    $text =~ s/<code>(.|\n)*?\<\/code>/ /ig;
### 다음 두 줄 추가
    $text =~ s/(^|\n)\{\{\{[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/ \n/igm;
    $text =~ s/(^|\n)\{\{\{([a-zA-Z0-9+]+)(\|(n|\d*|n\d+|\d+n))?[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/ \n/igm;
### 여기까지
    if ($interlink) {
        $text =~ s/''+/ /g;  # Quotes can adjacent to inter-site links
    ...
}

1.19. 페이지를 저장할 때 수행되는 매크로 도입

다음과 같이 DoPost 함수 내에 ProcessPostMacro() 함수를 삽입한다.
sub DoPost {
    ...
    # Remove "\r"-s (0x0d) from the string
    $string =~ s/\r//g;

### 다음 라인 추가
    $string = &ProcessPostMacro($string);
###
    # Lock before getting old page to prevent races
    &RequestLock() or die(T('Could not get editing lock'));
    ...

그 다음, 적당한 위치에 ProcessPostMacro() 함수를 통채로 작성한다.
sub ProcessPostMacro {
    my ($string) = @_;

    ### 여기에 사용할 매크로들을 나열한다
    $string = &PostMacroMySign($string);

    return $string;
}

이제 "작성시 변환되는 매크로"를 도입하고 싶다면, 적절한 변환 함수를 작성하고, 그 함수를 위의 ProcessPostMacro 안에서 다음과 같이 호출해준다.
    $string = &내가추가한함수($string);

또한, 미리보기 창에서도 이런 매크로가 정의되게 하기 위해서, DoPreview() 함수도 마찬가지로 수정한다.
sub DoPreview {
    $ClickEdit = 0;
    print &GetHttpHeader();
    print &GetHtmlHeader("$SiteName: " . T('Preview'), "Preview");
### 다음 라인을 아래 두 줄로 교체
#   print &WikiToHTML(&GetParam("text", undef));
    my ($textPreview) = &GetParam("text", undef);
    print &WikiToHTML(&ProcessPostMacro($textPreview));
###
}

1.19.1. <mysign> 매크로 도입

다음 함수를 적당한 위치에 추가하고, 위에서 언급한 ProcessPostMacro() 함수내에서 호출하도록 한다.
sub PostMacroMySign {
    my ($string) = @_;
    my ($authorAddr) = $ENV{REMOTE_ADDR};
    my ($timestamp) = CalcDay($Now) . " " . CalcTime($Now);
    my ($author) = &GetParam('username');

    if ($author ne "") {
    # 이 시점에서 [[ ]] 를 붙이는 것이 옳은가 확인할 것
        $author = "[[$author]]";
    } else {
        $author = $authorAddr;
# 아래의 주석을 해제하면 ip 끝자리를 xxx 로 표시한다
#       $author =~ s/\d+$/xxx/;
    }
    # 아래에 <mysign > 의 n 과 우측부등호 사이에 공백이 없게 할 것.
    $string =~ s/<mysign >/<mysign($author,$timestamp)>/g;

    return $string;
}

1.20. <mysign(name,time)> 매크로 도입

sub MacroSubst {
    ...
    # 원래 소스 코드에는 &lt; 와 &gt; 로 적혀 있는 것을, {{{ }}} 태그 사용을 위하여 
    # &__LT__; 와 &__GT__; 로 수정했다. 자세한 내용은 {{{ }}} 태그 도입 항목을 참조
    $txt =~ s/\&__LT__;goto\((.*)\)\&__GT__;/&MacroGoto($1)/gei;
    $txt =~ s/\&__LT__;history\((.*)\)\&__GT__;/&MacroHistory($1)/gei;
### 다음 라인을 추가
    $txt =~ s/\&__LT__;mysign\(([^,]+),(\d+-\d+-\d+ \d+:\d+.*)\)\&__GT__;/&MacroMySign($1, $2)/gei;
###
    return $txt;
}
적당한 위치에 MacroMySign 함수 전체를 삽입한다
sub MacroMySign {
    my ($author, $timestamp) = @_;
    return "\n<div align=\"right\">-- $author <small>$timestamp</small></div>\n";
}

1.21. <include> 매크로 출력을 html 변환

sub WikiToHTML {
    ...
    $SaveNumUrlIndex = 0;
    $pageText =~ s/$FS//g;              # Remove separators (paranoia)
### 다름 라인 추가
    $pageText = &MacroIncludeSubst($pageText);
###
    if ($RawHtml) {
    ...
}
sub MacroSubst {
    ...
    $txt =~ s/\&__LT__;RandomPage\((.*)\)\&__GT__;/&MacroRandom($1)/gei;
### 다음 라인 주석 처리
#   $txt =~ s/\&__LT__;Include\((.*)\)\&__GT__;/&MacroInclude($1)/gei;
    ...
### 다음 함수를 통채로 추가
sub MacroIncludeSubst {
    my ($txt) = @_;

    $txt =~ s/<Include\((.*)\)>/&MacroInclude($1)/gei;
    return $txt;
}

1.22. 테이블 정렬 방식 개선 및 rowspan 기능 추가

sub CommonMarkup {
    ...
    if ($doLines) { # 0 = no line-oriented, 1 or 2 = do line-oriented
        ...
        if ($UseHeadings) {
            s/(^|\n)\s*(\=+)\s+([^\n]+)\s+\=+/&WikiHeading($1, $2, $3)/geo;
### 다음 줄을 주석처리하고 그 아래의 내용을 추가한다.
#           s/((\|\|)+)/"<\/TD><TD COLSPAN=\"" . (length($1)\/2) . "\">"/ge if $TableMode;
            my %td_align = ("&__LT__;", "left", "&__GT__;", "right", "|", "center");
            s/((\|\|)*)(\|(&__LT__;|&__GT__;|\|)((v(\d*))?))/"<\/TD><TD align=\"$td_align{$4}\" COLSPAN=\""
                . ((length($1)\/2)+1) . ((length($5))?"\" ROWSPAN=\"" . ((length($7))?"$7":"2"):"") . "\">"/ge if $TableMode;
### 여기까지
        }
    }
    ...
}
sub WikiLinesToHtml {
    my ($pageText) = @_;
    my ($pageHtml, @htmlStack, $code, $depth, $oldCode);
    my ($tag);
### 다음 라인 추가
    my %td_align = ("&__LT__;", "left", "&__GT__;", "right", "|", "center");
###
    ...
    foreach (split(/\n/, $pageText)) {  # Process lines one-at-a-time
        ...
        } elsif (/^[ \t].*\S/) {
            $code = "PRE";
            $depth = 1;
### 다음 단락은 주석처리하고 그 아래의 내용을 추가한다
#       } elsif (s/^((\|\|)+)(.*)\|\|\s*$/"<TR VALIGN='CENTER' ALIGN='CENTER'><TD colspan='" . (length($1)\/2) . "'>$3<\/TD><\/TR>\n"/e) {
#           $code = 'TABLE';
#           $TableMode = 1;
#           $depth = 1;

        } elsif (s/^((\|\|)*)(\|(&__LT__;|&__GT__;|\|)((v(\d*))?))(.*)\|\|\s*$/"<TR VALIGN='CENTER' ALIGN='CENTER'>"
                . "<TD align=\"$td_align{$4}\" colspan=\""
                . ((length($1)\/2)+1) . ((length($5))?"\" ROWSPAN=\"" . ((length($7))?"$7":"2"):"") . "\">"
                . $8 . "<\/TD><\/TR>\n"/e) {
            $code = 'TABLE';
            $TableMode = 1;
            $depth = 1;
### 여기까지
        } elsif (/^IMG:(.*)$/) {        # luke added
            StoreImageTag($1);
        ...
    }
    ...
}

1.23. <calendar> 매크로 추가

MacroSubst 안에서
<   $txt =~ s/\&__LT__;calendar\(([-+]?\d+),([-+]?\d+)(,[^\n)]+)?\)\&__GT__;/&MacroCalendar($1, $2, $3)/gei;
>   $txt =~ s/\&__LT__;calendar\(([^,\n]+,)?([-+]?\d+),([-+]?\d+)\)\&__GT__;/&MacroCalendar($1, $2, $3)/gei;

MacroCalendar 안에서
<   my ($cal_year, $cal_month, $cal_mainpage) = @_;
>   my ($cal_mainpage, $cal_year, $cal_month) = @_;

<       return "&lt;calendar($cal_year,$cal_month$cal_mainpage)&gt;";
>       return "&lt;calendar($cal_mainpage$cal_year,$cal_month)&gt;";

<       $temp =~ s/^,//;
>       $temp =~ s/,$//;

<           return "&lt;calendar($cal_year,$cal_month$cal_mainpage)&gt;";
>           return "&lt;calendar($cal_mainpage$cal_year,$cal_month)&gt;";

전체 소스
sub MacroSubst {
    ...
### 다음 라인 추가
    $txt =~ s/\&__LT__;calendar\(([^,\n]+,)?([-+]?\d+),([-+]?\d+)\)\&__GT__;/&MacroCalendar($1, $2, $3)/gei;
###
    return $txt;
}
### 다음 함수를 적당한 곳에 추가
sub MacroCalendar {
    use Time::Local;
    my ($cal_mainpage, $cal_year, $cal_month) = @_;

    my $result='';
    my $cal_result='';
    my $cal_page;
    my @cal_color = ("red", "black", "black", "black", "black", "black", "blue", "green");
    my @cal_dow = (T('Su'), T('Mo'), T('Tu'), T('We'), T('Th'), T('Fr'), T('Sa'));
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Now);
    my ($this_year, $this_month, $this_day) = ($year, $mon, $mday);
    my $cal_time;
    my $cal_tdstyle;
    my $temp;

    # 달의 값이 13 이상이면 무효
    if (!($cal_month =~ /[-+]/) && ($cal_month > 12)) {
        return "&lt;calendar($cal_mainpage$cal_year,$cal_month)&gt;";
    }

    # prefix 처리
    if (length($cal_mainpage) != 0) {
        $temp = $cal_mainpage;
        $temp =~ s/,$//;
        $temp = &RemoveLink($temp);
        $temp = &FreeToNormal($temp);
        if (&ValidId($temp) ne "") {
            return "&lt;calendar($cal_mainpage$cal_year,$cal_month)&gt;";
        }
        $temp =~ s/\/.*$//;
        $cal_mainpage = "$temp/";
    }

    # 년도나 달에 0 을 인자로 받으면 올해 또는 이번 달
    $cal_year = $this_year+1900 if ($cal_year == 0);
    $cal_month = $this_month+1 if ($cal_month == 0);

    # 년도에 + 또는 - 가 있으면 올해로부터 변위 계산
    if ($cal_year =~ /\+(\d+)/ ) {
        $cal_year = $this_year+1900 + $1;
    } elsif ($cal_year =~ /-(\d+)/ ) {
        $cal_year = $this_year+1900 - $1;
    }

    # 달에 + 또는 - 가 있으면 이번 달로부터 변위 계산
    if ($cal_month =~ /\+(\d+)/ ) {
        $cal_month = $this_month+1 + $1;
        while ($cal_month > 12)  {
            $cal_month -= 12;
            $cal_year++;
        }
    } elsif ($cal_month =~ /-(\d+)/ ) {
        $cal_month = $this_month+1 - $1;
        while ($cal_month < 1) {
            $cal_month += 12;
            $cal_year--;
        }
    }

    # 1902년부터 2037년 사이만 지원함. 그 범위를 벗어나면 1902년과 2037년으로 계산
    $cal_year = 2037 if ($cal_year > 2037);
    $cal_year = 1902 if ($cal_year < 1902);

    # 달력 제목 출력
    $result .= "<table style=\"border:1 solid lightgrey;\">";
    $result .= "<caption style=\"padding:0; font-size:9pt; text-decoration:none;\">"
        ."<a href=\"$ScriptName?$cal_mainpage$cal_year-$cal_month\">"
        ."<font color=\"black\"><b>"
        .(length($cal_mainpage)?"$cal_mainpage<br>":"")
        ."$cal_year-$cal_month"
        ."</b></font>"
        ."</a>"
        ."</caption>";

    # 상단의 요일 출력
    $result .= "<tr>";
    for (0..6) {
        $result .= "<th style=\"line-height:100%; border:none;\" align=\"center\">"
            . "<font color=\"$cal_color[$_]\">$cal_dow[$_]</font></th>";
    }
    $result .= "</tr>";

    # 인자로 주어진 달의 1일날을 찾음
    $cal_time = timelocal(0,0,0,1,$cal_month-1,$cal_year);
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($cal_time);
    # 달력의 첫번째 날 찾음
    $cal_time -= $wday * (60 * 60 * 24);
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($cal_time);

    # 달력 그림
    for (1..6) {
        $result .= "<tr>";
        for (0..6) {
            $cal_page = ($year + 1900) . "-" . ($mon+1) ."-$mday";
            $cal_result = $mday;
            $cal_tdstyle = "line-height:100%;";
            if (($year == $this_year) && ($mon == $this_month) && ($mday == $this_day)) {
                $cal_tdstyle .= " border:1 solid lightgrey; background:yellow;";
            } else {
                $cal_tdstyle .= " border:none;";
            }

            if (-f &GetPageFile($cal_mainpage . $cal_page)) {
                $cal_tdstyle .= " text-decoration:underline; ";
                $cal_result = "<b>$cal_result</b>";
                $wday = 7;
            }
            if ($cal_month != ($mon+1)) {
                $cal_result = "<small>$cal_result</small>";
            }

            $result .= "<td style=\"$cal_tdstyle\" align=\"right\">"
                ."<a href=\"$ScriptName?$cal_mainpage$cal_page\">"
                ."<font color=\"$cal_color[$wday]\">"
                .$cal_result
                ."</font></a></td>";
            $cal_time += (60 * 60 * 24);
            ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($cal_time);
        }
        $result .= "</tr>";
        # 4 또는 5 줄로 끝낼 수 있으면 끝냄
        last if (($mon+1 > $cal_month) || ($year+1900 > $cal_year));
    }

    $result .= "</table>";
    return $result;
}

1.24. <wikiversion> 매크로 추가 (optional)

...
package UseModWiki;
use strict;
### 소스 제일 첫부분에 다음 라인들을 추가
use vars qw($WikiVersion $WikiRelease);
$WikiVersion = "0.92K3-ext1";
$WikiRelease = "2002-11-24";
###
local $| = 1;  # Do not buffer output (localized for mod_perl)
...
sub MacroSubst {
    ...
### 다음 라인 추가
    $txt =~ s/\&__LT__;wikiversion&__GT__;/&MacroWikiVersion()/gei;
###
    return $txt;
}
### 다음 함수를 적절한 곳에 추가
sub MacroWikiVersion {
    return &ScriptLink("action=version", $WikiVersion);
}
sub DoShowVersion {
    print &GetHeader("", T('Displaying Wiki Version'), "");
### 다음 라인을 교체
#   print "<p>UseModWiki version 0.92K2<p>\n";
    print "<p>UseModWiki version $WikiVersion ($WikiRelease)<p>\n";
###
    print &GetCommonFooter();
}

1.25. <vote(count[,scale])> 매크로 추가

sub MacroSubst {
    ...
### 다음 라인 추가
    $txt =~ s/\&__LT__;vote\((\d+)(,(\d+))?\)&__GT__;/&MacroVote($1,$3)/gei;
###
    return $txt;
}
# 다음 함수를 통채로 추가
sub MacroVote {
    my ($count, $scale) = @_;
    my $maximum = 1000;
    $scale = 10 if ($scale eq '');
    my $width = $count * $scale;
    $width = $maximum if ($width > $maximum);

    return "<table ".(($width)?"bgcolor=\"lightgrey\" ":"")
        ."width=\"$width\" style=\"border:1 solid gray;\">"
        ."<tr><td style=\"padding:0; border:none; font-size:8pt;\">$count"
        ."</td></tr></table>";
}

1.26. 존재하지 않는 페이지의 링크를 WikiX 스타일로 출력

$LinkFirstChar = 1;
등으로 정의해 준다.
# $LinkFirstChar 추가
use vars qw(@RcDays @HtmlPairs @HtmlSingle
    ...
    $ConfigFile $SOURCEHIGHLIGHT %SRCHIGHLANG $LinkFirstChar);
sub GetPageOrEditAnchoredLink {
    ...
### 다음 라인을 아래와 같이 수정
#   return $name . &GetEditLink($id,"?");
    if (($LinkFirstChar) && ($name =~ /(\[)?([^\/]*\/)?([a-zA-Z0-9\/]|[\x80-\xff][\x80-\xff])([^\]]*)(\])?/)) {
        return $2 . &GetEditLink($id,"<b>$3</b>") . $4;
    } else {
        return $name . &GetEditLink($id,"?");
    }
###
}

1.27. GetFullLinkList 함수에 파라메터 사용을 가능하게 함

sub GetFullLinkList {
### 다음 라인들을 추가
    my ($opt) = @_;
    my $opt_item;
    my %args = (            # default 값
            "unique" , 1,
            "sort", 1,
            "page", 1,
            "inter", 0,
            "url", 0,
            "exists", 2,
            "empty", 0,
            "search", "",
            "reverse", ""
    );
    foreach $opt_item (split('&',$opt)) {
        if ($opt_item =~ /^(.+)=(.+)$/) {
            $args{$1} = $2;
        }
    }
###
    ...
    my ($pagelink, $interlink, $urllink);
    my (@found, @links, @newlinks, @pglist, %pgExists, %seen);
### 다음 라인들을 교체
#   $unique = &GetParam("unique", 1);
#   $sort = &GetParam("sort", 1);
#   $pagelink = &GetParam("page", 1);
#   $interlink = &GetParam("inter", 0);
#   $urllink = &GetParam("url", 0);
#   $exists = &GetParam("exists", 2);
#   $empty = &GetParam("empty", 0);
#   $search = &GetParam("search", "");

    $unique = &GetParam("unique", $args{"unique"});
    $sort = &GetParam("sort", $args{"sort"});
    $pagelink = &GetParam("page", $args{"page"});
    $interlink = &GetParam("inter", $args{"inter"});
    $urllink = &GetParam("url", $args{"url"});
    $exists = &GetParam("exists", $args{"exists"});
    $empty = &GetParam("empty", $args{"empty"});
    $search = &GetParam("search", $args{"search"});
###

1.28. 페이지 제목을 클릭했을때 진정한 의미의 역링크 출력

### 다음 함수를 통채로 추가
sub GetReverseLink {
    my ($id) = @_;
    my $name = $id;

    if ($FreeLinks) {
        $name =~ s/_/ /g;  # Display with spaces
    }
    return &ScriptLink("reverse=$id", $name);
}
sub GetHeader {
    ...
### 다음 라인을 교체
#       $result .= $q->h1(&GetSearchLink($id));             # 원래 코드
#       $result .= $q->h1($header . &GetSearchLink($id));   # "사이트 로고" 관련해서 패치했던 코드
        $result .= $q->h1($header . &GetReverseLink($id));  # 이것이 최종 코드
###
    ...
}
sub DoOtherRequest {
    ...
    $search = &GetParam("search", "");
    if (($search ne "") || (&GetParam("dosearch", "") ne "")) {
        &DoSearch($search);
        return;
    }
### 다음 단락 추가
    $search = &GetParam("reverse", "");
    if ($search ne "") {
        &DoReverse($search);
        return;
    }
### 여기까지
    # Handle posted pages
    if (&GetParam("oldtime", "") ne "") {
    ...
}
# 다음 함수를 통채로 추가
sub DoReverse {
    my ($string) = @_;
    my @x = ();
    my $pagelines;

    if ($string eq '') {
        &DoIndex();
        return;
    }
    print &GetHeader('', &QuoteHtml(Ts('Links to %s', $string)), '');
    print '<br>';

    foreach $pagelines (&GetFullLinkList("sort=1&reverse=$string")) {
        my @pages = split(' ', $pagelines);
        @x = (@x, shift(@pages));
    }

    &PrintPageList(@x);

    if ($#x eq -1) {
        print T('No reverse link.') . "<br>";
    }
    print "<hr size=\"1\">" . Ts('Return to %s' , &GetPageLink($string)) . "<br>";

    print &GetCommonFooter();
}
# 다시 한 번 말하지만, 위의 "GetFullLinkList 함수에 파라메터 사용을 가능하게 함" 패치가 적용된 상태여야 한다.
sub GetFullLinkList {
    ...
### 다음 라인 교체
#   my ($name, $unique, $sort, $exists, $empty, $link, $search);
    my ($name, $unique, $sort, $exists, $empty, $link, $search, $reverse);
###
    my ($pagelink, $interlink, $urllink);
    ...
    $search = &GetParam("search", $args{"search"});
### 다음 라인 추가
    $reverse = &GetParam("reverse", $args{"reverse"});
###
    ...
            if (($search ne "") && !($link =~ /$search/)) {
                next;
            }
### 다음 단락 추가
            if ($reverse ne "") {
                my ($mainpage, $subpage) = ("", "");
                if ($reverse =~ /(.+)\/(.+)/) {
                    ($mainpage, $subpage) = ($1, $2);
                }
                if (!((split('/',$name))[0] eq $mainpage && $link eq "\/$subpage") && !($link eq $reverse)) {
                    next;
                }
            }

### 여기까지
            push(@newlinks, $link);
    ...
}

1.29. RemoveLink() 함수 추가

# 다음 함수를 통채로 추가
sub RemoveLink {
    my ($string) = @_;

    $string =~ s/<a href[^>]*>(\?<\/a>)?//ig;
    $string =~ s/<\/?b>//ig;
    $string =~ s/<\/a>//ig;

    return $string;
}

1.30. allpagesto 매크로 추가

sub MacroSubst {
    ...
### 추가
    $txt =~ s/\&__LT__;allpagesto\(([^\n]+)\)\&__GT__;/&MacroAllPagesTo($1)/gei;
###
    return $txt;
}
### 함수를 통채로 추가
sub MacroAllPagesTo {
    my ($string) = @_;
    my @x = ();
    my ($pagelines, $pagename, $txt);
    my $pagename;

    $string = &RemoveLink($string);
    $string = &FreeToNormal($string);
    if (&ValidId($string) ne "") {
        return "&lt;allpagesto($string)&gt;";
    }

    foreach $pagelines (&GetFullLinkList("sort=1&reverse=$string")) {
        my @pages = split(' ', $pagelines);
        @x = (@x, shift(@pages));
    }

    foreach $pagename (@x) {
        $txt .= ".... "  if ($pagename =~ m|/|);
        $txt .= &GetPageLink($pagename) . "<br>";
    }

    return $txt;
}

1.31. allpagesfrom 매크로 추가

sub MacroSubst {
    ...
### 다음라인 추가
    $txt =~ s/\&__LT__;allpagesfrom\(([^,\n]+)(,\d)?\)\&__GT__;/&MacroAllPagesFrom($1, $2)/gei;
###
    return $txt;
}
### 다음 함수를 통채로 추가
sub MacroAllPagesFrom {
    my ($string, $exists) = @_;
    my (@x, @links, $pagename, %seen, %pgExists);
    my $txt;

    $string = &RemoveLink($string);
    $string = &FreeToNormal($string);
    if (&ValidId($string) ne "") {
        return "&lt;allpagesfrom($string)&gt;";
    }

    if ($exists =~ /,(\d)/) {
        $exists = $1;
    } else {
        $exists = 2;
    }

    %pgExists = ();
    foreach $pagename (&AllPagesList()) {
        $pgExists{$pagename} = 1;
    }

    @x = &GetPageLinks($string, 1, 0, 0);

    foreach $pagename (@x) {
        $pagename = (split('/',$string))[0]."$pagename" if ($pagename =~ /^\//);
        if ($seen{$pagename} != 0) {
            next;
        }
        if (($exists == 0) && ($pgExists{$pagename} == 1)) {
            next;
        }
        if (($exists == 1) && ($pgExists{$pagename} != 1)) {
            next;
        }
        $seen{$pagename}++;
        push (@links, $pagename);
    }
    @links = sort(@links);

    foreach $pagename (@links) {
        $txt .= ".... "  if ($pagename =~ m|/|);
        $txt .= &GetPageOrEditLink($pagename) . "<br>";
    }

    return $txt;
}

1.32. orphanedpages 매크로 추가

sub MacroSubst {
    ...
### 다음 라인 추가
    $txt =~ s/\&__LT__;orphanedpages\(([-+])?(\d+)\)\&__GT__;/&MacroOrphanedPages($1, $2)/gei;
###
    return $txt;
}
### 다음 함수를 통채로 추가
sub MacroOrphanedPages {
    my ($less_or_more, $criterion) = @_;
    my (@allPages, $page, $pageline, @pages, $id, @x);
    my %numOfReverse;
    my $txt;

    @allPages = &AllPagesList();

    foreach $page (@allPages) {
        $numOfReverse{$page} = 0;
    }

    foreach $pageline (&GetFullLinkList("exists=1&sort=0")) {
        my @links = split(' ', $pageline);
        my $id = shift(@links);
        my $link;
        foreach $link (@links) {
            $link = (split('/',$id))[0]."$link" if ($link =~ /^\//);
            next if ($id eq $link);
            $numOfReverse{$link}++;
        }
    }

    foreach $page (@allPages) {
        next if (($less_or_more eq "-") && ($numOfReverse{$page} > $criterion));
        next if (($less_or_more eq "+") && ($numOfReverse{$page} < $criterion));
        next if (($less_or_more eq "") && ($numOfReverse{$page} != $criterion));
        $txt .= ".... " if ($page =~ m|/|);
        $txt .= &GetPageLink($page) . "<br>";
    }

    return $txt;
}

1.33. wantedpages 매크로 추가

sub MacroSubst {
    ...
### 다음 라인 추가
    $txt =~ s/\&__LT__;wantedpages\&__GT__;/&MacroWantedPages()/gei;
###
    return $txt;
}
### 다음 함수를 통채로 추가
sub MacroWantedPages {
    my ($pageline, @found, $page);
    my %numOfReverse;
    my $txt;

    foreach $pageline (&GetFullLinkList("exists=0&sort=0")) {
        my @links = split(' ', $pageline);
        my $id = shift(@links);
        foreach $page (@links) {
            $page = (split('/',$id))[0]."$page" if ($page =~ /^\//);
            push(@found, $page) if ($numOfReverse{$page} == 0);
            $numOfReverse{$page}++;
        }
    }
    @found = sort(@found);

    foreach $page (@found) {
        $txt .= ".... " if ($page =~ m|/|);
        $txt .= &GetPageOrEditLink($page, $page) . " ("
            . &ScriptLink("action=links&editlink=1&reverse=$page", $numOfReverse{$page})
            . ")<br>";
    }

    return $txt;
}

1.34. includenotoc 매크로 추가

...
use vars qw(@RcDays @HtmlPairs @HtmlSingle
    ...
    $ConfigFile $SOURCEHIGHLIGHT %SRCHIGHLANG $LinkFirstChar $FS_lt $FS_gt);  # 끝에 $FS_lt $FS_gt 추가
...
sub InitLinkPatterns {
    ...
    $FS3 = $FS . "3";   # The FS character is not allowed in user data.
### 다음 두 줄 추가
    $FS_lt = $FS . "lt";
    $FS_gt = $FS . "gt";
###
    ...
}
sub WikiToHTML {
    ...
### 다음 두 라인 추가
    $pageText =~ s/$FS_lt/&lt;/g;
    $pageText =~ s/$FS_gt/&gt;/g;
###
    return &RestoreSavedText($pageText);
}
sub MacroIncludeSubst {
    my ($txt) = @_;

    $txt =~ s/<include\((.*)\)>/&MacroInclude($1)/gei;
### 다음 라인 추가
    $txt =~ s/<includenotoc\((.*)\)>/&MacroInclude($1, "notoc")/gei;
###
    return $txt;
}
### 다음 함수를 새로 작성
sub MacroInclude {
    my ($name, $opt) = @_;

    if ($OpenPageName eq $name) { # Recursive Include 방지
        return "";
    }

    my $fname = &GetPageFile($name);    # 존재하지 않는 파일이면 그냥 리턴
    if (!(-f $fname)) {
        return "";
    }

    my $data = &ReadFileOrDie($fname);
    my %SubPage = split(/$FS1/, $data, -1);  # -1 keeps trailing null fields

    if (!defined($SubPage{"text_default"})) {
        return "";
    }

    my %SubSection = split(/$FS2/, $SubPage{"text_default"}, -1);
    my %TextInclude = split(/$FS3/, $SubSection{'data'}, -1);

    # includenotoc 의 경우
    $TextInclude{'text'} =~ s/<toc>/$FS_lt."toc".$FS_gt/gei if ($opt eq "notoc");
    return $TextInclude{'text'};
}

1.35. #EXTERN 명령어 추가

use vars qw(@RcDays @HtmlPairs @HtmlSingle
    ...
### 환경변수 추가
    $EditGuideInExtern $SizeTopFrame $SizeBottomFrame);
### wiki.pl 에 기본값을 적어주고, config.pl 에서 별도로 설정한다.
$EditGuideInExtern = 0; # 1 = show edit guide in bottom frame, 0 = don't show
$SizeTopFrame = 160;
$SizeBottomFrame = 110;
sub BrowsePage {
    ...
        } else {  # Not a valid target, so continue as normal page
            $id = $oldId;
            $oldId = '';
        }
    }
### 다음 단락 추가
    if (substr($Text{'text'}, 0, 8) eq '#EXTERN ') {
        $oldId = &GetParam('oldid', '');
        my ($externURL) = ($Text{'text'} =~ /\#EXTERN\s+([^\s]+)/);
        if ($externURL =~ /^$UrlPattern$/) {
            &BrowseExternUrl($id, $oldId, $externURL);
            return;
        }
    }
### 여기까지
    $MainPage = $id;
    $MainPage =~ s|/.*||;  # Only the main page name (remove subpage)
    ...
}
### 다음 함수를 통채로 추가
sub BrowseExternUrl {
    my ($id, $oldId, $url) = @_;
    my $sizeBottomFrame = $SizeBottomFrame * $EditGuideInExtern;

    if (&GetParam('InFrame','') eq '1') {
        print &GetHeader($id, "$id [InTopFrame]",$oldId);
        print &GetMinimumFooter();
        return;
    } elsif ((&GetParam('InFrame','') eq '2') && ($EditGuideInExtern)) {
        print &GetHeader($id, "$id [InBottomFrame]",$oldId);
        print "<hr>\n";
        print &GetEditGuide($id, '');
        print &GetMinimumFooter();
        return;
    } else {
        print &GetHttpHeader();
        print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\">\n";
        print "<html>&lt;</html>html<html>&gt;</html>\n";
        print "<title>$SiteName: $id</title>\n";
        print "<frameset rows=\"$SizeTopFrame,*,$sizeBottomFrame\" cols=\"1\" frameborder=\"0\">\n";
        print "  <frame src=\"$ScriptName?action=browse&InFrame=1&id=$id&oldid=$oldId\" noresize>\n";
        print "  <frame src=\"$url\" noresize>\n";
        print "  <frame src=\"$ScriptName?action=browse&InFrame=2&id=$id&oldid=$oldId\" noresize>\n" if ($EditGuideInExtern);
        print "  <noframes>\n";
        print "  <body>\n";
        print "  <p>".T('You need the web browser which supports frame tag.')."\n";
        print "  </body>\n";
        print "  </noframes>\n";
        print "</frameset>\n";
        print "<html>&lt;</html>/html<html>&gt;</html>\n";
        return;
    }
}
sub GetHeader {
    ...
    return $result  if ($embed);
### 다음 라인 추가
    return $result if (&GetParam('InFrame','') eq '2');
### 여기까지

### 다음 단락 수정
#   if ($oldId ne '') {
#       $result .= $q->h3('(' . Ts('redirected from %s',
#                                                            &GetEditLink($oldId, $oldId)) . ')');
#   }

    my $topMsg = "";
    if ($oldId ne '') {
        $topMsg .= '('.Ts('redirected from %s',&GetEditLink($oldId, $oldId)).')  ';
    }
    if (&GetParam('InFrame','') eq '1') {
        $topMsg .= '('.Ts('%s includes external page',&GetEditLink($id,$id)).')';
    }
    $result .= $q->h3($topMsg) if (($oldId ne '') || (&GetParam('InFrame','') eq '1'));
### 여기까지
    if ((!$embed) && ($LogoUrl ne "")) {
    ...
    } else {
        $result .= $q->h1($header . $title);
    }
### 아래는 "페이지 상단에 Alt+Z 할당" 패치에서 추가한 부분이다. 
### 그 패치를 적용하지 않았다면 아래 단락은 무시해도 된다.
    if (&GetParam('InFrame','') eq '') {
        $result .= "\n<div align=\"right\"><a accesskey=\"z\" name=\"#PAGE_TOP\" href=\"#PAGE_BOTTOM\">".T('Bottom') . "</a></div>\n";
    }
### 여기까지
    if (&GetParam("toplinkbar", 1)) {
    ...
}
sub GetHtmlHeader {
    ...
### 다음 단락 교체
    # added luke
#   if ($ClickEdit) {
#       if ($FreeLinks) {
#           $id = &FreeToNormal($id);
#       }
#       $bodyExtra .= qq(ondblclick="location.href='$ScriptName?action=edit&id=$id'");
#   }
    # end

    if (&GetParam('InFrame','') ne '') {
        $html .= qq(<base target="_parent">\n);
    } else {
        if ($ClickEdit) {
            if ($FreeLinks) {
                $id = &FreeToNormal($id);
            }
            $bodyExtra .= qq(ondblclick="location.href='$ScriptName?action=edit&id=$id'");
        }
    }
### 여기까지
    ...
}
sub GetMinimumFooter {
### 다음 단락 추가
    if (&GetParam('InFrame','') ne '') {
        return $q->end_html;
    }
###
    ...
}

1.36. InterWiki 로 된 이미지 화일 처리

sub InterPageLink {
### 다음 라인 수정
#   my ($id) = @_;
    my ($id, $useImage) = @_;
###
    my ($name, $site, $remotePage, $url, $punct);

    ($id, $punct) = &SplitUrlPunct($id);

    $name = $id;
    ($site, $remotePage) = split(/:/, $id, 2);
    $url = &GetSiteUrl($site);
    return ("", $id . $punct)  if ($url eq "");
    $remotePage =~ s/&amp;/&/g;  # Unquote common URL HTML
    $url .= $remotePage;
### 다음 단락 추가
    if ($useImage && ($url =~ /^(http:|https:|ftp:).+\.$ImageExtensions$/)) {
        $url = $1 if ($url =~ /^https?:(.*)/ && $1 !~ /^\/\//);
        return ("<img $ImageTag src=\"$url\" alt=\"$id\">", $punct);
    }
### 여기까지
    return ("<a href=\"$url\">$name</a><a href=\"$url\" target=\"_blank\"><img src=\"./emoticon/newwindow.gif\" border=\"0\" alt=\"" . T('Open in a New Window') . "\" align=\"absbottom\"></a>", $punct);
}
위에서 볼 수 있듯이 InterPageLink 에 두번째 파라메터가 추가되었다. 호출해주는 곳 각각을 적절히 수정해주어야 한다.
sub CommonMarkup {
    ...
### 다름 라인 수정
#       s/$InterLinkPattern/&StoreInterPage($1)/geo;
        s/$InterLinkPattern/&StoreInterPage($1, $useImage)/geo;
###
    ...
}
sub StoreInterPage {
### 다음 라인 수정
#   my ($id) = @_;
    my ($id, $useImage) = @_;
###
    my ($link, $extra);

### 다음 라인 수정
#   ($link, $extra) = &InterPageLink($id);
    ($link, $extra) = &InterPageLink($id, $useImage);
###
    # Next line ensures no empty links are stored
    $link = &StoreRaw($link)  if ($link ne "");
    return $link . $extra;
}

1.37. mms 프로토콜 인식

    $UrlProtocols = "http|https|ftp|afs|news|nntp|mid|cid|mailto|wais|mms|"      # 뒤에 "mms|" 를 추가
                                    . "prospero|telnet|gopher";

1.38. IMG: 태그 개선

IMG:옵션 이미지경로

또는

IMG:옵션
이미지경로

sub CommonMarkup {
    ...
        s/\[$InterLinkPattern\]/&StoreBracketInterPage($1, "")/geo;
### 다음 라인 추가.
        s/IMG:([^<>\n]*)\n?$UrlPattern/&StoreImgUrl($1, $2, $useImage)/geo;
###
        s/$UrlPattern/&StoreUrl($1, $useImage)/geo;
    ...
}
### 다음 함수를 통채로 추가
sub StoreImgUrl {
    my ($imgTag, $name, $useImage) = @_;
    my ($link, $extra);

    $ImageTag = $imgTag;
    ($link, $extra) = &UrlLink($name, $useImage);
    # Next line ensures no empty links are stored
    $link = &StoreRaw($link)  if ($link ne "");
    $ImageTag = "";
    return $link . $extra;
}

1.39. 존재하지 않는 페이지의 링크 스타일을 사용자가 결정할 수 있게 함

sub GetPageOrEditAnchoredLink {
    ...
#   다음 줄 이하를 재수정
#   if (($LinkFirstChar) && ($name =~ ... /)) {;

    if ((&GetParam('linkstyle', $LinkFirstChar))
            && ($name =~ /(\[)?([^\/]*\/)?([a-zA-Z0-9\/]|[\x80-\xff][\x80-\xff])([^\]]*)(\])?/)) {
        return $2 . &GetEditLink($id,"<b>$3</b>") . $4;
    } else {
        return $name . &GetEditLink($id,"?");
    }
### 여기까지
}
sub DoEditPrefs {
    ...
    print '<br>', &GetFormCheck('toplinkbar', 1,
                            T('Show link bar on top'));
### 다음 단락 추가
    print '<br>', &GetFormCheck('linkstyle', $LinkFirstChar,
            T('Use wikiX style for the links to empty pages'));
###
    print '<br>', &GetFormCheck('linkrandom', 0,
                                                T('Add "Random Page" link to link bar'));
    ...
}
sub DoUpdatePrefs {
    ...
    &UpdatePrefCheckbox("toplinkbar");
### 다음 라인 추가
    &UpdatePrefCheckbox("linkstyle");
###
    &UpdatePrefCheckbox("linkrandom");
    ...
}

1.40. userlist 매크로 추가

sub MacroSubst {
### 다음 라인 추가
    $txt =~ s/\&__LT__;userlist\&__GT__;/&MacroUserList()/gei;
###
    return $txt;
}
### 다음 함수를 통채로 추가
sub MacroUserList {
    my (@userlist, $result);
    my $usernumber;
    opendir(USERLIST, $UserDir);
    @userlist = readdir(USERLIST);
    close(USERLIST);
    shift @userlist;
    shift @userlist;
    @userlist = sort @userlist;
    foreach $usernumber (0..(@userlist-1)) {
        @userlist[$usernumber] =~ s/(.*)\.db/($1)/gei;
        @userlist[$usernumber] = &StorePageOrEditLink("@userlist[$usernumber]", "@userlist[$usernumber]") . "<br>";
    }

    $result = "@userlist";

    return $result;
}

1.41. titleindex action 추가

sub DoOtherRequest {
   ...
        } elsif ($action eq "index") {
            &DoIndex();
### 다음 단락 추가
        } elsif ($action eq "titleindex") {
            &DoTitleIndex();
###
        } elsif ($action eq "help") {               # luke added
            &DoHelp();       
   ...
}
### 다음 함수를 통채로 추가
sub DoTitleIndex {
    my (@list);
    my $index;
    print "Content-type: text/plain\n\n";
    @list = &AllPagesList();
    foreach $index (@list) {
        print $index."\r\n";
    }
}

1.42. form 을 생성할 때 form 의 이름을 부여할 수 있도록 함

sub GetFormStart {
### 다음 라인을 아래 단락으로 교체
#   return $q->startform("POST", "$ScriptName", "application/x-www-form-urlencoded");

    my ($name) = @_;

    if ($name eq '') {
        return $q->startform("POST", "$ScriptName", "application/x-www-form-urlencoded");
    } else {
        return $q->startform(-method=>"POST", -action=>"$ScriptName", -enctype=>"application/x-www-form-urlencoded" ,-name=>"$name") ;
    }
###
}

이미지 화일 확장자 대문자 인식

sub InitLinkPatterns {
....
	$ImageExtensions = "(GIF|JPG|PNG|BMP|JPEG|gif|jpg|png|bmp|jpeg)"; #### 바꿔준다.
}

이 수정본 편집일: 2003-1-9 12:22 am (변경사항 [d])
Permalink | 변경내역 보기 [h] | 현재 수정본 보기 | 38 번째 수정본 소스 보기