--- test/html-webhacc/WebHACC/Output.pm 2008/07/20 16:53:10 1.2
+++ test/html-webhacc/WebHACC/Output.pm 2008/08/17 05:06:21 1.22
@@ -1,6 +1,8 @@
package WebHACC::Output;
use strict;
+
require IO::Handle;
+use Scalar::Util qw/refaddr/;
my $htescape = sub ($) {
my $s = $_[0];
@@ -14,8 +16,19 @@
return $s;
};
+my $htescape_value = sub ($) {
+ my $s = $_[0];
+ $s =~ s/&/&/g;
+ $s =~ s/</g;
+ $s =~ s/>/>/g;
+ $s =~ s/"/"/g;
+ return $s;
+};
+
sub new ($) {
- return bless {nav => []}, shift;
+ require WebHACC::Input;
+ return bless {nav => [], section_rank => 1,
+ input => WebHACC::Input->new}, shift;
} # new
sub input ($;$) {
@@ -23,7 +36,7 @@
if (defined $_[1]) {
$_[0]->{input} = $_[1];
} else {
- delete $_[0]->{input};
+ $_[0]->{input} = WebHACC::Input->new;
}
}
@@ -42,6 +55,18 @@
return $_[0]->{handle};
} # handle
+sub has_error ($;$) {
+ if (@_ > 1) {
+ if (defined $_[1]) {
+ $_[0]->{has_error} = 1;
+ } else {
+ delete $_[0]->{has_error};
+ }
+ }
+
+ return $_[0]->{has_error};
+} # has_error
+
sub set_utf8 ($) {
binmode shift->{handle}, ':utf8';
} # set_utf8
@@ -71,40 +96,180 @@
sub start_tag ($$%) {
my ($self, $tag_name, %opt) = @_;
- $self->html ('<' . $htescape->($tag_name)); # escape for safety
+ $self->html ('<' . $htescape_value->($tag_name)); # escape for safety
if (exists $opt{id}) {
my $id = $self->input->id_prefix . $opt{id};
- $self->html (' id="' . $htescape->($id) . '"');
+ $self->html (' id="' . $htescape_value->($id) . '"');
delete $opt{id};
}
for (keys %opt) { # for safety
- $self->html (' ' . $htescape->($_) . '="' . $htescape->($opt{$_}) . '"');
+ $self->html (' ' . $htescape_value->($_) . '="' .
+ $htescape_value->($opt{$_}) . '"');
}
$self->html ('>');
} # start_tag
sub end_tag ($$) {
- shift->html ('' . $htescape->(shift) . '>');
+ shift->html ('' . $htescape_value->(shift) . '>');
} # end_tag
sub start_section ($%) {
my ($self, %opt) = @_;
- $self->html ('
{section_rank}++;
+ $self->html (qq[
input->id_prefix . $opt{id};
- $self->html (' id="' . $htescape->($id) . '"');
- push @{$self->{nav}}, [$id => $opt{short_title} || $opt{title}]
- unless $self->input->nested;
+ my $prefix = $self->input->id_prefix;
+ $opt{parent_id} ||= $prefix;
+ my $id = $prefix . $opt{id};
+ $self->html (' id="' . $htescape->($id) . '">');
+ if ($self->{section_rank} == 2 or length $opt{parent_id}) {
+ my $st = $opt{short_title} || $opt{title};
+ push @{$self->{nav}},
+ [$id => $st => $opt{text}] if $self->{section_rank} == 2;
+
+ $self->start_tag ('script');
+ $self->html (qq[ addSectionLink ('$id', ']);
+ $self->nl_text ($st, text => $opt{text});
+ if (defined $opt{parent_id}) {
+ $self->html (q[', '] . $opt{parent_id});
+ }
+ $self->html (q[') ]);
+ $self->end_tag ('script');
+ }
+ } else {
+ $self->html ('>');
}
- $self->html ('>
' . $htescape->($opt{title}) . '
');
+ my $section_rank = $self->{section_rank};
+ $section_rank = 6 if $section_rank > 6;
+ $self->html ('');
+ $self->nl_text ($opt{title}, text => $opt{text});
+ $self->html ('');
} # start_section
sub end_section ($) {
my $self = shift;
$self->html ('');
$self->{handle}->flush;
+ $self->{section_rank}--;
} # end_section
+sub start_error_list ($%) {
+ my ($self, %opt) = @_;
+
+ if (defined $opt{role}) {
+ if ($opt{role} eq 'parse-errors') {
+ $opt{id} ||= 'parse-errors-list';
+ delete $opt{role};
+ } elsif ($opt{role} eq 'structure-errors') {
+ $opt{id} ||= 'document-errors-list';
+ delete $opt{role};
+ } elsif ($opt{role} eq 'transfer-errors') {
+ $opt{id} ||= 'transfer-errors-list';
+ delete $opt{role};
+ }
+ }
+
+ $self->start_tag ('dl', %opt);
+
+ delete $self->{has_error}; # reset
+} # start_error_list
+
+sub end_error_list ($%) {
+ my ($self, %opt) = @_;
+
+ my $no_error_message = 'No error found.';
+
+ if (defined $opt{role}) {
+ if ($opt{role} eq 'parse-errors') {
+ $self->end_tag ('dl');
+ ## NOTE: For parse error list, the |add_source_to_parse_error_list|
+ ## method is invoked at the end of |generate_source_string_section|,
+ ## since that generation method is invoked after the error list
+ ## is generated.
+ $no_error_message = 'No parse error found.';
+ } elsif ($opt{role} eq 'structure-errors') {
+ $self->end_tag ('dl');
+ $self->add_source_to_parse_error_list ('document-errors-list');
+ $no_error_message = 'No structural error found.';
+ } elsif ($opt{role} eq 'transfer-errors') {
+ $self->end_tag ('dl');
+ $no_error_message = 'No transfer error found.';
+ } else {
+ $self->end_tag ('dl');
+ }
+ } else {
+ $self->end_tag ('dl');
+ }
+
+ unless ($self->{has_error}) {
+ $self->start_tag ('p', class => 'no-errors');
+ $self->nl_text ($no_error_message);
+ }
+} # end_error_list
+
+sub add_source_to_parse_error_list ($$) {
+ my $self = shift;
+
+ $self->script (q[addSourceToParseErrorList ('] . $self->input->id_prefix .
+ q[', '] . shift () . q[')]);
+} # add_source_to_parse_error_list
+
sub start_code_block ($) {
shift->html ('
');
} # start_code_block
@@ -113,10 +278,55 @@
shift->html ('
');
} # end_code_block
-sub code ($$) {
- shift->html ('
' . $htescape->(shift) . '');
+sub code ($$;%) {
+ my ($self, $content, %opt) = @_;
+ $self->start_tag ('code', %opt);
+ $self->text ($content);
+ $self->html ('');
} # code
+sub script ($$;%) {
+ my ($self, $content, %opt) = @_;
+ $self->start_tag ('script', %opt);
+ $self->html ($content);
+ $self->html ('');
+} # script
+
+sub dt ($$;%) {
+ my ($self, $content, %opt) = @_;
+ $self->start_tag ('dt', %opt);
+ $self->nl_text ($content, text => $opt{text});
+} # dt
+
+sub select ($$%) {
+ my ($self, $options, %opt) = @_;
+
+ my $selected = $opt{selected};
+ delete $opt{selected};
+
+ $self->start_tag ('select', %opt);
+
+ my @options = @$options;
+ while (@options) {
+ my $opt = shift @options;
+ if ($opt->{options}) {
+ $self->html ('
]);
+ }; # $options
+
+ $out->start_section (id => 'input', title => 'Input');
+ $out->html (q[]);
+
+ $out->start_section (id => 'input-url', title => 'By URL',
+ parent_id => 'input');
+ $out->start_tag ('form', action => './#result-summary',
+ 'accept-charset' => 'utf-8',
+ method => 'get');
+ $out->start_tag ('input', type => 'hidden', name => '_charset_');
+
+ $out->start_tag ('p');
+ $out->start_tag ('label');
+ $out->nl_text ('URL');
+ $out->text (': ');
+ $out->start_tag ('input',
+ name => 'uri',
+ type => 'url',
+ value => $decode->(scalar $cgi->get_parameter ('uri')));
+ $out->end_tag ('label');
+
+ $out->start_tag ('p');
+ $out->start_tag ('button', type => 'submit');
+ $out->nl_text ('Check');
+ $out->end_tag ('button');
+
+ $options->('url');
+
+ $out->end_tag ('form');
+ $out->end_section;
+
+ ## TODO: File upload
+
+ $out->start_section (id => 'input-text', title => 'By direct input',
+ parent_id => 'input');
+ $out->start_tag ('form', action => './#result-summary',
+ 'accept-charset' => 'utf-8',
+ method => 'post');
+ $out->start_tag ('input', type => 'hidden', name => '_charset_');
+
+ $out->start_tag ('p');
+ $out->start_tag ('label');
+ $out->nl_text ('Document source to check');
+ $out->text (': ');
+ $out->start_tag ('br');
+ $out->start_tag ('textarea',
+ name => 's');
+ my $s = $decode->($cgi->get_parameter ('s'));
+ $out->html ($htescape_value->($s)) if defined $s;
+ $out->end_tag ('textarea');
+ $out->end_tag ('label');
+
+ $out->start_tag ('p');
+ $out->start_tag ('button', type => 'submit',
+ onclick => 'form.method = form.s.value.length > 512 ? "post" : "get"');
+ $out->nl_text ('Check');
+ $out->end_tag ('button');
+
+ $options->('text');
+
+ $out->end_tag ('form');
+ $out->end_section;
+
+ $out->script (q[
+ if (!document.webhaccNavigated &&
+ document.getElementsByTagName ('textarea')[0].value.length > 0) {
+ showTab ('input-text');
+ document.webhaccNavigated = false;
+ }
+ ]);
+
+ $out->end_section;
+} # generate_input_section
sub encode_url_component ($$) {
shift;