[첫화면으로]UseModWiki소스수정/섹션단위수정

마지막으로 [b]

1. 섹션 단위 수정
1.1. 구현하면서 신경쓴 부분
1.2. 사용법
1.3. 부작용
1.4. wiki.pl 수정
1.5. wiki.css 수정
1.6. translation/korean.pl 수정
1.7. 추가 업데이트 내역
1.8. 사용자 의견

1. 섹션 단위 수정

"== 섹션 제목 =="을 출력할 때 우측에 "편집" 링크를 띄우고, 그 섹션만 수정할 수 있도록 한다.

웬만하면 안 건드리려고 했는데, 페이지의 양이 조금만 늘어나도 당장 나부터 정신이 없어서 수정하기 너무 힘들기에, 다른 것에 앞서 이것부터... =.=;

1.1. 구현하면서 신경쓴 부분

== 섹션1 ==
== 셕션2 ==
섹션2의 내용
=== 섹션2.1 ===
섹션2.1의 내용
=== 셕션2.2 ===
셕션2.2의 내용
== 셕션3 ==

1.2. 사용법

당장 이 페이지만 봐도 알 수 있을테니 생략.

한 가지, 섹션 편집을 할 경우 변경사항요약 부분에 자동으로 "섹션 제목 - "의 형태로 값이 들어가게 하였다. 혹시 이게 맘에 안 든다면 아래 소스 수정에서 "# summary 를 해당 섹션 제목으로"라는 주석이 붙어 있는 단락을 주석 처리해 주면 됨.

1.3. 부작용

위에서 언급했듯이, 페이지를 출력할 때는 헤드라인으로 처리되지 않는데, 수정하거나 저장할 때는 헤드라인으로 인식되어서 오류를 낼 가능성이 있다.

예를 들어 어떤 페이지의 소스가 아래와 같다면,
 == 이건 진짜 헤드라인 (1) ==
 {{{
 == 이건 {{{ }}} 안에 있어서 그냥 출력되는 부분 (2) ==
 }}}
 == 이건 진짜 헤드라인 (3) ==

(1)과 (3)에는 편집하기 링크가 있고 (2)에는 없을 것이다. 그런데 (3)의 링크를 눌렀는데, 편집화면에는 (2)의 내용이 나온다던가, 편집화면에도 제대로 나왔는데 막상 저장 버튼을 눌렀더니 그 내용이 (2)의 자리가 바뀌어 있다던가 하는 경우가 있을 수 있다는 것.

그런 일이 발생하지 않도록 신경을 쓴다고는 썼는데, 빠뜨린 게 있을 지 모르니 발견하면 알려 주시면 감사하겠습니다.


섹션 단위로 편집을 하다가 "미리 보기" 버튼을 누르면, 페이지 전체가 아니라 해당 섹션 내용만 가지고 결과를 출력한다. 이것 자체로 큰 문제는 아닌데 (오히려 나은 것 같기도 하고), 해당 섹션 이외의 부분의 영향을 받는 부분은 이상하게 나올 수 있다. 예를 들어서 Diary/티스토리에서유즈모드로링크문제에서 제목 헤드라인의 편집을 눌러서 미리 보기를 해보면 footer 부분이 우측이 아니라 아래로 나오는 걸 볼 수 있다.

1.4. wiki.pl 수정

전역 변수 추가:
### 패치를 위해 추가된 내부 전역 변수
use vars qw(%RevisionTs $FS_lt $FS_gt $StartTime $Sec_Revision $Sec_Ts
    ...
    $UseShortcut $UseShortcutPage
    $SectionNumber);               # 여기 추가

다른 페이지를 include할 때 그 페이지 안에 있는 헤드라인 서식에는 "noedit"라는 마크를 붙여 둔다.
sub MacroInclude {
    ...
    $txt =~ s/(<thread\()([-+]?\d+(,\d+)?)(\)>)/$1$name,$2$4/gi;

# 섹션 단위 편집 - include 될 때는 하지 않음
    $txt =~ s/((^|\n)[\ \t\f]*\=+[\ \t\f]+[^\n]+)([\ \t\f]+\=+)/$1${FS}noedit$FS$3/go;

    return $txt;
}

헤드라인 서식을 마크업할 때 편집하기 링크를 추가
sub WikiHeading {
    my ($pre, $depth, $text) = @_;

    $depth = length($depth);
    $depth = 6  if ($depth > 6);
    $text =~ s/^#\s+/&WikiHeadingNumber($depth,$')/e; # $' == $POSTMATCH
### 섹션 단위 편집 - 여기서부터 수정
#   return $pre . "<H$depth>$text</H$depth>\n";
    my $edit_section;
    if ($text =~ s/${FS}noedit$FS//) {  # include 된 내용의 경우는 스킵
    } elsif (&GetParam('revision', '') eq '') {
        $SectionNumber++;
        $edit_section = '<SPAN class="editsection">['.
            &ScriptLink("action=edit&id=$pageid&section=$SectionNumber",&T("edit")).
            ']</SPAN>';
        $edit_section = '' if ($depth == 1);
    }
    return $pre . "<H$depth>$edit_section$text</H$depth>\n";
######
}

페이지 편집 모드에서 section 파라메터가 있으면 해당 섹션의 내용만 불러옴
sub DoEdit {
    ...
    $oldText = $Text{'text'};
    if ($preview && !$isConflict) {
        $oldText = $newText;
    }
### 섹션 단위 편집 - 편집할 때     여기서부터 추가
    my $section = &GetParam('section', '');
    if ($section >= 1) {
        my $temp_text;
        my (@h_depth, @h_pos);
        my $num = 0;

        $temp_text = $oldText;

        # {{{ }}} 등 헤드라인이 올 수 없는 것들을 먼저 제외
        %SaveUrl = ();
        $SaveUrlIndex = 0;
        $temp_text = &store_raw_codes($temp_text);

        # 남은 텍스트에서 헤드라인들의 목록을 뽑는다
        while ($temp_text =~ /(^[ \t]*(\=+)\s+[^\n]+\s+\=+\s*$)/gm) {
            $num++;
            $h_pos[$num] = pos($temp_text) - length($1);        # 각 섹션의 시작 포지션
            $h_depth[$num] = length($2);

            # summary 를 해당 섹션 제목으로
            if ($num == $section) {
                my $h_str = $1;
                $h_str =~ /^[ \t]*\=+\s+(#\s+)?([^\n]+)\s+\=+\s*$/;
                $h_str = $2;
                $h_str =~ s/"/&quot;/g;
                $q->param("summary", "$h_str - ".&GetParam("summary", ""));
            }
        }
        $num++;
        $h_pos[$num] = length($temp_text);
        $h_depth[$num] = 1;

        # 같은 depth 의 다음 헤드라인을 찾음
        my $next;
        for ($next = $section+1; ($next <= $#h_depth) && ($h_depth[$section] < $h_depth[$next]); $next++) {}

        # 수정할 섹션의 텍스트만 추출
        my $offset = $h_pos[$section];
        my $length = $h_pos[$next] - $offset;
        $temp_text = substr($temp_text, $offset, $length);

        # 제외했던 내용 복원
        $temp_text = &RestoreSavedText($temp_text);
        %SaveUrl = ();
        $SaveUrlIndex = 0;

        # $oldText 바꿔치기
        $oldText = $temp_text;
        $header .= " ". &T('(section)');
    }
##### 여기까지
    $editRows = &GetParam("editrows", 20);
    $editCols = &GetParam("editcols", 65);

    ...

        if ($revision ne "") {
            print &GetHiddenValue("revision", $revision), "\n";
        }
# ECode
        my $ecode = &simple_crypt(length($id).substr(&CalcDay($Now),5));
        print &GetHiddenValue("ecode","$ecode")."\n";
###
### 섹션 단위 편집 - 여기 단락 추가
        if ($section >= 1) {
            print &GetHiddenValue("section", $section)."\n";
        }
##### 여기까지
        print &GetTextArea('text', $oldText, $editRows, $editCols);
        $summary = &GetParam("summary", "*");
    ...
}

페이지를 저장할 때, 사용자가 입력한 해당 섹션의 내용과 기존 페이지 내용 중 다른 섹션의 내용을 합쳐서 처리함
sub DoPostMain {
    ...
    $old = $Text{'text'};
    $oldrev = $Section{'revision'};
    $pgtime = $Section{'ts'};

### 섹션 단위 편집 - 저장할 때         여기서부터 추가
    my $section = &GetParam('section', '');
    if ($section >= 1) {
        my $temp_text;
        my (@h_depth, @h_pos);
        my $num = 0;

        $temp_text = $old;

        # {{{ }}} 등 헤드라인이 올 수 없는 것들을 먼저 제외
        %SaveUrl = ();
        $SaveUrlIndex = 0;
        $temp_text = &store_raw_codes($temp_text);

        # 남은 텍스트에서 헤드라인들의 목록을 뽑는다
        while ($temp_text =~ /(^[ \t]*(\=+)\s+[^\n]+\s+\=+\s*$)/gm) {
            $num++;
            $h_pos[$num] = pos($temp_text) - length($1);        # 각 섹션의 시작 포지션
            $h_depth[$num] = length($2);
        }
        $num++;
        $h_pos[$num] = length($temp_text);
        $h_depth[$num] = 1;

        # 같은 depth 의 다음 헤드라인을 찾음
        my $next;
        for ($next = $section+1; ($next <= $#h_depth) && ($h_depth[$section] < $h_depth[$next]); $next++) {}

        # 입력폼에서 넘어온 텍스트를, 그 외 앞뒤 섹션과 결합
        $temp_text = substr($temp_text, 0, $h_pos[$section]).
            $string.
            substr($temp_text, $h_pos[$next]);

        # 제외했던 내용 복원
        $temp_text = &RestoreSavedText($temp_text);
        %SaveUrl = ();
        $SaveUrlIndex = 0;

        # $string 바꿔치기
        $string = $temp_text;
    }
##### 여기까지
    $preview = 0;
    $preview = 1  if (&GetParam("Preview", "") ne "");

    ...

    if (($oldrev > 0) && ($newAuthor && ($oldtime != $pgtime))) {
        &ReleaseLock();
### 섹션 단위 편집 - 충돌이 발생하면 전체 페이지 편집으로
        $q->param('section','');
#####
        if ($oldconflict>0) {  # Conflict again...
            &DoEdit($id, 2, $pgtime, $string, $preview);

    ...
}

다음 함수 통채로 추가:
# 섹션 단위 편집을 위한 내부 함수
sub store_raw_codes {
    my ($text) = @_;

    # 코드는 GetPageLinks 에서 다시 가져옴
    $text =~ s/(<html>((.|\n)*?)<\/html>)/&StoreRaw($1)/ige;
    $text =~ s/(^|\n)(\{\{\{[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1.&StoreRaw($2)."\n"/igem;
    $text =~ s/(^|\n)(\{\{\{([a-zA-Z0-9+]+)(\|(n|\d*|n\d+|\d+n))?[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1.&StoreRaw($2)."\n"/igem;
    $text =~ s/(^|\n)(\{\{\{#!((\w+)( .+)?)[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1.&StoreRaw($2)."\n"/igem;
    $text =~ s/(<nowiki>(.|\n)*?\<\/nowiki>)/&StoreRaw($1)/ige;
    $text =~ s/(<pre>(.|\n)*?\<\/pre>)/&StoreRaw($1)/ige;
    $text =~ s/(<code>(.|\n)*?\<\/code>)/&StoreRaw($1)/ige;

    return $text;
}

1.5. wiki.css 수정

헤드라인에 들어가는 편집 링크의 span 스타일 - [위키페디아의 스타일쉬트]를 참조했음
/* 섹션 별 편집 */
.editsection {
    font-size: 90%;
    float: right;
    margin-right: 0.5em;
}

1.6. translation/korean.pl 수정

다음 항목 추가
(section)
(부분)

1.7. 추가 업데이트 내역

ext1.106a

ext2.1e

ext2.5c

1.8. 사용자 의견

아... 막상 만들어 보니, 진짜 페이지 편집할 때 편하긴 하군요. 특히 페이지 분량은 긴데 내가 고치려는 부분은 뒷부분에 있을 때... 왜 진작에 하지 않았을까 후회될 정도. ^_^
-- Raymundo 2007-2-5 3:30 pm

바벨의 도서관 같은 경우는 페이지의 diff를 볼 때 변경사항 부분도 마크업을 해버리기 때문에, 변경사항 중에 헤드라인이 있으면 거기서부터 번호를 매겨버립니다. 따라서 diff화면에서 바로 edit 링크를 누르면 자기가 의도한 섹션이 아니라 엇갈려 나올테니, 아예 diff 화면에서 edit 링크가 나오지 않게 바꿔버릴 수 있겠네요. 제 홈에서는 최근변경내역->페이지 diff->여기에서 바로 수정으로 갈 수 있는 게 좋아서 그냥 놔둡니다만, 필요하실 지 몰라서 적어둡니다.

sub WikiHeading {
    ...
        $edit_section = '' if ($depth == 1);
        $edit_section = '' if (&GetParam('diff', '') ne '');      # 이 줄 추가
    }
    return $pre . "<H$depth>$edit_section$text</H$depth>\n";
}
-- Raymundo 2007-2-7 10:19 am

우와. 감사합니다.
-- Nyxity 2007-2-7 10:28 am

Hi, Raymundo

possibly you thought about this, hint: edit by sections also in versions (only a suggestion, no waiting time for its implementation since I am working with that in localhost). Hope it helps, thanks for this great patch.

Regards, --JuanmaMP
-- JustSameJuanmaMP 2009-8-28 2:01 am

Good job :-)

I considered it when I was making this patch. But I wondered if there would be such need (edit sections in the past revisions ). And I refered Wikipedia and Moniwiki. Wikipedia doesn't support it. Moniwiki supports it but not correctly. Therefore, I decided not to support it, either, hehehe. :-D

Anyway, if someone need to edit a page of past revisions frequently, your work would be helpful.
-- Raymundo 2009-8-28 10:42 am

Good Night over there, Raymundo.
I just don't understand what does it mean?
Where does it go the particle "noedit" to?
Moreover, there's nothing into parentheses.
Thanks for shed light, as far as you can.

if ($text =~ s/${FS}noedit$FS//) { # include 된 내용의 경우는 스킵
}

Sincerely.
Juanma
-- JuanmaMP 2012-7-7 3:02 am

Well, well, well... You asked me about "noedit"...?

Okay, Welcome to the world of ancient black magic :-)

It has some historical background.
- First, I made "include" macro.
- Next, I made "section edit" feature.
- Then, I realized that, if a user clicks "edit" link on a heading and (unluckily) the heading is in the "included page", all things would be spoiled, because there is not such section in the "including page"

So I needed to make the included contents not to have edit links, and I did it as following:

1) Insert a mark "${FS}noedit${FS}" into all the headings in the included content. This is done in MacroInclude().
2) In markup stage, if a heading contains the mark, skip that heading, that is, not insert the edit link. This is done in the elsif block in WikiHeading(), as you've seen.

3) There is one more thing to do. We need to remove the "noedit" mark before we print the page. This is done in... the code you wrote above :-) There's nothing in if block, but substitution is done in the parentheses. This removes the mark, replacing it with an empty string.

You can see the example in
- TestPage : this page includes a subpage
- TestPage/SubPage : this page is included
-- Raymundo 2012-7-7 2:34 pm

Good Evening, Raymundo.
Big thanks for clarification.
Could you maintain TestPage and TestPage/SubPage, let's say, until tomorrow (from now. It will be enough), in order to catching the idea?

Have a good Sunday!.
-- JuanmaMP 2012-7-7 9:38 pm

Sure, they shall remain until next year, LOL
-- Raymundo 2012-7-8 2:25 pm

Thanks. Indeed, it is perfectly possible that I could to need an extension of the one-year deadline. (Sometimes, I feel myself as HAL when sings Daisy. Haha!).
Cheers!.
-- JuanmaMP 2012-7-8 8:32 pm

Your reasoning helps me to take awareness (remembering, best said) about kinds of these patches.
I use, sometimes, "print &GetHiddenValue('parameter', 1)"; for instance, into "IncludeRaw" (in this case).
Then, in "WikiHeading" I use the parameter value to discriminate scenarios. Hope it functional, too. I guess ...
Good morning over there.
-- JuanmaMP 2012-7-12 6:35 am

This feature, also leaves the door to rawinclusions by section (other new feature) ... .
-- JuanmaMP 2012-7-12 6:52 am
이름:  
Homepage:
내용:
 

위키위키분류
각주:
1. 만일 사용자가 편집하려는 게 오직 "섹션2의 내용" 부분 뿐인 경우라면, 하위 섹션의 내용이 같이 나온 게 번잡할 수는 있겠다. (특히 하위 섹션의 갯수나 내용이 많다면) 그렇지만 그런 경우라도 자신이 편집할 내용이 제일 윗부분에 있으므로 별로 불편할 일은 없어 보인다.

마지막 편집일: 2012-7-12 6:52 am (변경사항 [d])
963 hits | Permalink | 변경내역 보기 [h] | 페이지 소스 보기