--- test/html-webhacc/WebHACC/Output.pm 2008/07/27 10:33:46 1.9 +++ test/html-webhacc/WebHACC/Output.pm 2008/08/15 12:11:56 1.18 @@ -16,6 +16,15 @@ return $s; }; +my $htescape_value = sub ($) { + my $s = $_[0]; + $s =~ s/&/&/g; + $s =~ s//>/g; + $s =~ s/"/"/g; + return $s; +}; + sub new ($) { require WebHACC::Input; return bless {nav => [], section_rank => 1, @@ -46,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 @@ -75,66 +96,108 @@ 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 ('(shift) . '>'); + shift->html ('(shift) . '>'); } # end_tag sub start_section ($%) { my ($self, %opt) = @_; + my $class = 'section'; if (defined $opt{role}) { if ($opt{role} eq 'parse-errors') { $opt{id} ||= 'parse-errors'; $opt{title} ||= 'Parse Errors Section'; $opt{short_title} ||= 'Parse Errors'; + $class .= ' errors'; delete $opt{role}; } elsif ($opt{role} eq 'structure-errors') { $opt{id} ||= 'document-errors'; $opt{title} ||= 'Structural Errors'; $opt{short_title} ||= 'Struct. Errors'; + $class .= ' errors'; + delete $opt{role}; + } elsif ($opt{role} eq 'transfer-errors') { + $opt{id} ||= 'transfer-errors'; + $opt{title} ||= 'Transfer Errors'; + $opt{short_title} ||= 'Trans. Errors'; + $class .= ' errors'; delete $opt{role}; } elsif ($opt{role} eq 'reformatted') { $opt{id} ||= 'document-tree'; $opt{title} ||= 'Reformatted Document Source'; $opt{short_title} ||= 'Reformatted'; + $class .= ' dump'; delete $opt{role} } elsif ($opt{role} eq 'tree') { $opt{id} ||= 'document-tree'; $opt{title} ||= 'Document Tree'; $opt{short_title} ||= 'Tree'; + $class .= ' dump'; delete $opt{role}; } elsif ($opt{role} eq 'structure') { $opt{id} ||= 'document-structure'; $opt{title} ||= 'Document Structure'; $opt{short_title} ||= 'Structure'; + $class .= ' dump'; + delete $opt{role}; + } elsif ($opt{role} eq 'subdoc') { + $class .= ' subdoc'; + delete $opt{role}; + } elsif ($opt{role} eq 'source') { + $opt{id} ||= 'source-string'; + $opt{title} ||= 'Document Source'; + $opt{short_title} ||= 'Source'; + $class .= ' source'; + delete $opt{role}; + } elsif ($opt{role} eq 'result') { + $opt{id} ||= 'result-summary'; + $opt{title} ||= 'Result'; + $class .= ' result'; delete $opt{role}; } } $self->{section_rank}++; - $self->html ('
html (qq[
input->id_prefix . $opt{id}; - $self->html (' id="' . $htescape->($id) . '"'); - push @{$self->{nav}}, - [$id => $opt{short_title} || $opt{title} => $opt{text}] - if $self->{section_rank} == 2; + 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}]; + + $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 ('>'); } my $section_rank = $self->{section_rank}; $section_rank = 6 if $section_rank > 6; - $self->html ('>'); + $self->html (''); $self->nl_text ($opt{title}, text => $opt{text}); $self->html (''); } # start_section @@ -156,33 +219,48 @@ } 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') { - delete $opt{role}; $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') { - delete $opt{role}; $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 ($$) { @@ -296,9 +374,30 @@ return join '/', @r; }; # $get_node_path +my $get_object_path = sub ($) { + my $node = shift; + my @r; + while (defined $node) { + my $ref = ref $node; + $ref =~ /([^:]+)$/; + my $rs = $1; + my $node_name = $node->node_name; + if (defined $node_name) { + $rs .= ' ' . $htescape->($node_name) . ''; + } + $node = undef; + unshift @r, $rs; + } + return join '/', @r; +}; # $get_object_path + sub node_link ($$) { my ($self, $node) = @_; - $self->xref ($get_node_path->($node), target => 'node-' . refaddr $node); + if ($node->isa ('Message::IF::Node')) { + $self->xref ($get_node_path->($node), target => 'node-' . refaddr $node); + } else { + $self->html ($get_object_path->($node)); + } } # node_link { @@ -344,6 +443,9 @@ $msg =~ s{{text}}{ defined $opt{text} ? $htescape->($opt{text}) : '' }ge; + $msg =~ s{{value}}{ + defined $opt{value} ? $htescape->($opt{value}) : '' + }ge; $msg =~ s{{local-name}}{ UNIVERSAL::can ($node, 'manakai_local_name') ? $htescape->($node->manakai_local_name) : '' @@ -400,19 +502,28 @@ - +

]); $self->nl_text (q[WebHACC:Heading]); - $self->html ('

'); + $self->html (q[]); } # html_header sub generate_input_section ($$) { my ($out, $cgi) = @_; + require Encode; + my $decode = sub ($) { + if (defined $_[0]) { + return Encode::decode ('utf-8', $_[0]); + } else { + return undef; + } + }; # $decode + my $options = sub ($) { my $context = shift; - $out->html (q[

]); + $out->html (q[

]); $out->nl_text (q[Options]); $out->start_tag ('div'); @@ -482,7 +593,7 @@ $out->nl_text ('Setting innerHTML'); $out->text (': '); $out->start_tag ('input', name => 'e', - value => scalar $cgi->get_parameter ('e')); + value => $decode->(scalar $cgi->get_parameter ('e'))); $out->end_tag ('label'); } @@ -490,9 +601,12 @@ }; # $options $out->start_section (id => 'input', title => 'Input'); + $out->html (q[]); - $out->start_section (id => 'input-url', title => 'By URL'); - $out->start_tag ('form', action => './', 'accept-charset' => 'utf-8', + $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_'); @@ -503,24 +617,25 @@ $out->start_tag ('input', name => 'uri', type => 'url', - value => $cgi->get_parameter ('uri')); + value => $decode->(scalar $cgi->get_parameter ('uri'))); $out->end_tag ('label'); - $options->('url'); - $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; - $out->end_tag ('fieldset'); - ## TODO: File upload - $out->start_section (id => 'input-text', title => 'By direct input'); - $out->start_tag ('form', action => './', 'accept-charset' => 'utf-8', + $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_'); @@ -531,22 +646,30 @@ $out->start_tag ('br'); $out->start_tag ('textarea', name => 's'); - my $s = $cgi->get_parameter ('s'); - $out->text ($s) if defined $s; + my $s = $decode->($cgi->get_parameter ('s')); + $out->html ($htescape_value->($s)) if defined $s; $out->end_tag ('textarea'); $out->end_tag ('label'); - $options->('text'); - $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