ODF-lpOD_Helper

 view release on metacpan or  search on metacpan

lib/ODF/lpOD_Helper.pm  view on Meta::CPAN

=head2 $boolean = $elt->His_text_container()

Returns TRUE if C<$elt> is a paragraph, heading or span.

=head2 $newelt = $elt->Hsplit_element_at($offset)

C<Hsplit_element_at> is like XML::Twig's C<split_at> but also knows how
to split text:s nodes.

If C<$elt> is a textual leaf (PCDATA, text:s, etc.) it is split, otherwise
it's first textual child is split.  Even a single-character leaf may be "split"
if $offset==0 or 1, see below.

The "right half" is moved to a new next sibling node, which is returned.

$offset must be between 0 and the existing length, inclusive.
If $offset is 0 then all existing content is moved to the new sibling
and the original node will be empty upon return.
if $offset equals the existing length then the new sibling will be empty.

If a text:s node is split then the new node will also be a text:s node
"containing" the appropriate number of spaces.  The 'text:c' attribute will
be zero if the node is "empty".

If a text:tab or text:line-break node is split then if $offset==0 the new node
will be an empty PCDATA node,
or if $offset==1 the original will be transmuted in-place to become
an empty PCDATA node.

=cut

sub ODF::lpOD::Element::His_textual {
  my $elt = shift;
  $elt->passes(TEXTLEAF_FILTER)
}
sub ODF::lpOD::Element::His_text_container {
  my $elt = shift;
  $elt->passes(TEXTCONTAINER_FILTER)
}

sub ODF::lpOD::Element::Hsplit_element_at {
  my ($elt, $offset) = @_;
  confess "Wrong number of arguments" unless @_==2;
  # see XML::Twig::split_at
  my $text_elt= $elt->His_textual() ? $elt
                                    : $elt->first_child(TEXTLEAF_FILTER)
                                        || confess("no textual leaf found");
  if ($text_elt->tag eq 'text:s') {
    my $existing_count = $text_elt->get_attribute('c') // 1;

    my $right_count = $existing_count - $offset;
    confess ivis 'offset $offset exceeds existing text:s count($existing_count)'
      if $right_count < 0;
    $text_elt->set_attribute('c', $offset); # possibly zero
    my $result = $text_elt->insert_element("text:s", position => NEXT_SIBLING);
    $result->set_attribute('c', $right_count); # possibly zero
    return $result
  }
  elsif ($text_elt->tag eq '#PCDATA') {
    my $existing_len = length($text_elt->text);
    confess ivis 'offset $offset exceeds existing pcdata length ($existing_len)'
      if $offset > $existing_len;
    return $text_elt->split_at($offset);
  }
  elsif ($offset == 0) {
#my $para = $elt->passes(PARA_FILTER) ? $elt : $elt->parent(PARA_FILTER);
#btw dvis 'BEFORE TRANSMUTE $para = ',fmt_tree($para);
#btw dvis 'BEFORE TRANSMUTE $elt = ',fmt_tree($elt);
    my $result =
         $text_elt->insert_element($text_elt->clone, position => NEXT_SIBLING);
#btw dvis '$result ',fmt_tree($result);
    # *TRANSMUTE* the original node to an empty PCDATA node
    $text_elt->del_atts();
    if (defined $text_elt->atts) {
      delete($text_elt->{att}) // oops; # Peeking into XML::Twig internals!
    }
    my @unhandled = grep{
                      ! /^(?:next_|prev_|first_|last_|parent|gi|empty|former)/
                    } keys %$text_elt;
    oops "unhandled left-over member(s) @unhandled" if @unhandled;
    $text_elt->set_tag("#PCDATA");
    # unpleasantly looking into ODF::lpOD internals...
    my $class = $ODF::lpOD::Element::CLASS{'#PCDATA'} // oops;
    bless $text_elt, $class;
    $text_elt->set_text("");
    return $result;
  }
  elsif ($offset == 1) {
    my $result = $text_elt->insert_element('#PCDATA', position=>NEXT_SIBLING);
    $result->set_text(""); # unnecessary?
    return $result;
  }
  else {
    confess "Hsplit_element_at : invocant $elt has no textual leaf"
  }
}# Hsplit_element_at

=head2 $context->Hget_text()

=head2 $context->Hget_text(prune_cond => COND)

Gets the combined "virtual text" in or below C<$context>,
by default including in nested paragraphs (e.g. in Frames or Tables).
The special nodes which represent tabs, line-breaks and
consecutive spaces are expanded to the corresponding characters.

Option B<prune_cond> may be used to omit text below specified node types
(see C<Hnext_elt>).

=head3 B<Note>

C<ODF::lpOD::TextElement::get_text()> with option I<recursive -E<gt> TRUE>
looks like it should do the same thing as C<Hget_text()>, but it has bugs:

=over 4

=item 1.

The special nodes for tab, etc. are expanded only when they are the
immediate children of $context.  With the 'recursive'
option #PCDATA nodes in nested paragraphs are expanded but tabs, etc.



( run in 1.438 second using v1.01-cache-2.11-cpan-995e09ba956 )