表紙 | 新規 | 編集 | 編集 | 差分 | 一覧 | RSS | 検索 | 閲覧履歴 | 作成履歴 | 更新履歴

text_to_html関数 - YukiWikiベースのPonyWikiのソースを読んでみる その20

YukiWikiベースのPonyWikiのソースを読んでみる その20

YukiWIki書式で保存されているデータをhtml化する関数。

処理の流れは以下の通り。

sub text_to_html {
	my ($txt, %option) = @_;

	my (@toc);
	my $verbatim;
	my $tocnum = 0;
	my (@saved, @result);

	my @open_tag;
	my ($depth, $nest_1st);

	push(@result, "<p>");
	unshift(@saved, "</p>");

	foreach (split(/\r?\n/, $txt)) {
		chomp;
		# verbatim.
		if ($verbatim->{func}) {
			if (/^\Q$verbatim->{done}\E$/) {
				undef $verbatim;
				push(@result, splice(@saved));
			} else {
				push(@result, $verbatim->{func}->($_));
			}
			next;
		}
		
		# non-verbatim follows.
		push(@result, shift(@saved)) if (@saved and $saved[0] eq '</pre>' and /^[^ \t]/);
		
		if (/^(\*{1,5})(.+)/) {
			# $hn = 'h2', 'h3', 'h4', 'h5' or 'h6'
			my $hn = "h" . (length($1) + 1);
			# Set $nest_1st
			if (!$nest_1st) { $nest_1st = length($1);}
			#
			my $tmp_depth = length($1);
		
			if($depth == $tmp_depth) {
				push(@result, splice(@saved), qq(</div>\n<$hn><a name="i$tocnum"> </a>) . &inline($2) . qq(</$hn>\n<div class="$hn).qq(level">));
			} elsif ($depth < $tmp_depth) { # nest inc →
				push(@result, splice(@saved), qq(<$hn><a name="i$tocnum"> </a>) . &inline($2) . qq(</$hn>\n<div class="$hn).qq(level">));
				$depth = $tmp_depth;
				$open_tag[$depth] = 1;
			} elsif ($depth > $tmp_depth) { # nest dec ←
				$depth = $tmp_depth;
				my $open_tag_cnt;
				my $i;
				
				if($nest_1st > $tmp_depth) {
					$nest_1st = $tmp_depth;
					$i = 1;
				} else {
					$i=$depth;
				}
				for(; $i < 7; $i++){
					$open_tag_cnt = $open_tag_cnt + $open_tag[$i];
					$open_tag[$i] = 0;
				}
				
				if($open_tag_cnt){
					push(@result, splice(@saved));
				}
				while($open_tag_cnt) {
					push(@result,qq(</div>));
					$open_tag_cnt--;
				}
				push(@result, splice(@saved), qq(<$hn><a name="i$tocnum"> </a>) . &inline($2) . qq(</$hn><div class="$hn).qq(level">));
				$open_tag[$depth] = 1;
			}
			
			if($form{keitai}){
				my $index_no = $tocnum +2;
				my $cookedpage = &encode($form{mypage});
				push(@toc, '-' x length($1) . qq( <a href="$url_cgi?mycmd=read&amp;mypage=$cookedpage&amp;mypart=$index_no">) . &remove_tag(&inline($2)) . qq(</a>\n));
			} else {
				push(@toc, '-' x length($1) . qq( <a href="#i$tocnum">) . &remove_tag(&inline($2)) . qq(</a>\n));
			}

# part edit
			if(!$form{mypart}){ # (携帯電話向け)部分読みの時は部分編集は表示しない
				my $cookedpage = &encode($form{mypage});
				$cookedpage =~ s/%/%%/g;
				push(@result, sprintf(qq(<div class="partinfo"><a class="partedit" title="$resource{editthispart}" href="$url_cgi?mycmd=edit&amp;mypage=$cookedpage&amp;mypart=%d">$resource{editthispart}</a> <a class="partedit" title="$resource{returntop}" href="$url_cgi?$cookedpage#top">$resource{returntop}</a></div>), $tocnum + 2)) if ($option{'partinfo'});		# Walrus add [part edit]
				push(@result, "<p>");
				unshift(@saved, "</p>");
			}
			$tocnum++;
		} elsif (/^(-{2,3})\($/) {
			if ($& eq '--(') {
				$verbatim = { func => \&inline, done => '--)', class => 'verbatim-soft' };
			} else {
				$verbatim = { func => \&escape, done => '---)', class => 'verbatim-hard' };
			}
			&back_push('pre', 1, \@saved, \@result, " class='$verbatim->{class}'");
		} elsif (/^\/\//) {
			# This is comment out. nop.
		} elsif (/^----/) {
			push(@result, splice(@saved), '<hr>');
		} elsif (/^(-{1,3})(.+)/) {
			&back_push('ul', length($1), \@saved, \@result);
			push(@result, '<li>' . &inline($2) . '</li>');
		} elsif (/^(={1,3})(.+)/) {
			&back_push('ol', length($1), \@saved, \@result);
			push(@result, '<li>' . &inline($2) . '</li>');
		} elsif (/^:([^:]+):(.+)/) {
			&back_push('dl', 1, \@saved, \@result);
			push(@result, '<dt>' . &inline($1) . '</dt>', '<dd>' . &inline($2) . '</dd>');
		} elsif (/^(>{1,3})(.+)/) {
			&back_push('blockquote', length($1), \@saved, \@result);
			push(@result, &inline($2));
		} elsif (/^$/) {
			push(@result, splice(@saved));
			unshift(@saved, "</p>");
			push(@result, "<p>");
		} elsif (/^(\s+.*)$/) {
			&back_push('pre', 1, \@saved, \@result);
			push(@result, &escape($1)); # Not &inline, but &escape
		} elsif (/^\,(.*?)[\x0D\x0A]*$/) {
			&back_push('table', 1, \@saved, \@result, ' border="1"');
			#######
			# This part is taken from Mr. Ohzaki's Perl Memo and Makio Tsukamoto's [[WalWiki]].
			# XXXXX
			my $tmp = "$1,";
			my @value = map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_} ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);
			my @align = map {(s/^\s+//) ? ((s/\s+$//) ? ' align="center"' : ' align="right"') : ''} @value;
			my @colspan = map {($_ eq '==') ? 0 : 1} @value;
			for (my $i = 0; $i < @value; $i++) {
				if ($colspan[$i]) {
					while ($i + $colspan[$i] < @value and $value[$i + $colspan[$i]] eq '==') {
						$colspan[$i]++;
					}
					$colspan[$i] = ($colspan[$i] > 1) ? sprintf(' colspan="%d"', $colspan[$i]) : '';
					$value[$i] = sprintf('<td%s%s>%s</td>', $align[$i], $colspan[$i], &inline($value[$i]));
				} else {
					$value[$i] = '';
				}
			}
			push(@result, join('', '<tr>', @value, '</tr>'));
			# XXXXX
			#######
		} elsif (/^\#(\w+)(\((.*)\))?/) {
			# BlockPlugin.
			my $original_line = $_;
			my $plugin_name = $1;
			my $argument = &escape($3);
			my $result = $plugin_manager->call($plugin_name, 'block', $argument);
			if (defined($result)) {
				push(@result, splice(@saved));
			} else {
				$result = $original_line;
			}
			push(@result, $result);
		} else {
			push(@result, &inline($_));
		}
	}
#
	if ($depth > 0) { # 見出しの<div>を全てクローズ
		my $open_tag_cnt;
		
		for(my $i; $i < 7; $i++){
			$open_tag_cnt = $open_tag_cnt + $open_tag[$i];
			$open_tag[$i] = 0;
		}
		
		if($open_tag_cnt){
			push(@result, splice(@saved));
		}
		while($open_tag_cnt) {
			push(@result,qq(</div>));
			$open_tag_cnt--;
		}
	}
#
	push(@result, splice(@saved));
	
	if ($option{toc} && !$form{mypart}) {
		# Convert @toc (table of contents) to HTML.
		# This part is taken from Makio Tsukamoto's [[WalWiki]].
		my (@tocsaved, @tocresult);
		foreach (@toc) {
			if (/^(-{1,5})(.*)/) {
				&back_push('ul', length($1), \@tocsaved, \@tocresult);
				push(@tocresult, '<li>' . $2 . '</li>');
			}
		}
		push(@tocresult, splice(@tocsaved));
		
		# Insert "table of contents".
		if (@tocresult) {
			unshift(@tocresult, qq(<h2>$resource{table_of_contents}</h2>));
		# Insert CSS <div class="index"> - </div>
			unshift(@tocresult, qq(<div class="index">));
			push(@tocresult, "</div>");
		}
		
		unshift(@result, qq(<div class="h1level">));
		push(@result, qq(</div>));
		my $return_html = join("\n",@tocresult,@result);
		$return_html =~ s/<p>\n<\/p>//mg;
		
		return $return_html;
	} else {
		my $return_html = join("\n",@result);
		$return_html =~ s/<p>\n<\/p>//mg;
		
		return $return_html;
	}
}

''TrackBack'' - http://you-like.to/cgi-bin/ponytail/yukiwiki/wiki.cgi/text_to_html%b4%d8%bf%f4

先頭へ