Changeset 5573


Ignore:
Timestamp:
11/18/09 06:27:14 (2 years ago)
Author:
MichaelTempest
Message:

Item2369: Add rowspan support to the WYSIWYG editor
This also fixed a bug in how Web.WikiWord links are rendered, if the link is the only text in the table cell.

Tables are no longer "normalised" when converting from HTML to TML by appending |'s so that every row has the same number of |'s. The logic to do so when supporting rowspans is complex (read: likely to be buggy) and the "normalisation" feature is seldom used (it only had any effect if the HTML has a table with a hole in it.) Taking out the normalisation does not result in loss of content.

Location:
trunk/WysiwygPlugin
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/WysiwygPlugin/data/System/WysiwygPlugin.txt

    r5355 r5573  
    141141 
    142142---+++ Overlapping styles 
    143 Because Foswiki uses a "best guess" approach to some formatting, it allows overlapping of tags in a way forbidden by HTML, and it is impossible to guarantee 100% that formating in the original Foswiki document will still be there when the same document is loaded and then saved through the WysiwygPlugin. The most obvious case of this is to do with styles. For example, the sentence 
     143Because Foswiki uses a "best guess" approach to some formatting, it allows overlapping of tags in a way forbidden by HTML, and it is impossible to guarantee 100% that formatting in the original Foswiki document will still be there when the same document is loaded and then saved through the WysiwygPlugin. The most obvious case of this is to do with styles. For example, the sentence 
    144144<verbatim> 
    145145*bold _bold-italic* italic_ 
     
    155155which is correct by construction, but does not render correctly in Foswiki. This problem is unfortunately unavoidable due to the way TML works. 
    156156 
     157---+++ Rowspan processing needs %SYSTEMWEB%.TablePlugin 
     158 
     159WysiwygPlugin is able to convert tables with cells that span rows into TML. This requires syntax provided by the %SYSTEMWEB%.TablePlugin (that is, the =| ^ |= markup). WysiwygPlugin will therefore only perform row-span related conversion if %SYSTEMWEB%.TablePlugin is enabled. %SYSTEMWEB%.TablePlugin is enabled by default and hence WysiwygPlugin converts tables with cells that span rows between TML and HTML by default. 
     160 
     161If %SYSTEMWEB%.TablePlugin is *not* enabled, then TML table cells containing only =^= are not converted to rowspans, and HTML tables containing rowspans are not converted to TML. 
     162 
    157163---++ Plugin Info 
    158164 
     
    170176|  Release: | %$RELEASE% | 
    171177|  Change History: | | 
     178|  18 Nov 2009 | Foswikitask:Item2369: Convert tables with cells that span rows | 
    172179|  22 Oct 2009 | Foswikitask:Item2183: Protect div style= by default | 
    173180|  18 Sep 2009 | Foswikitask:Item1980: Prevent dataloss when saving a topic in Wysiwyg where there are a pair of sticky tags inside verbatim tags | 
  • trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/HTML2TML/Node.pm

    r3986 r5573  
    823823} 
    824824 
    825 # probe down into a list type to determine if it 
     825# probe down into a table to determine if it 
    826826# can be converted to TML. 
    827827sub _isConvertableTable { 
     
    831831        return 0; 
    832832    } 
     833 
     834    my $rowspan = undef; 
     835    $rowspan    = [] if Foswiki::Func::getContext()->{'TablePluginEnabled'}; 
    833836 
    834837    my $kid = $this->{head}; 
     
    843846                return 0; 
    844847            } 
    845             my $row = $kid->_isConvertableTableRow($options); 
     848            my $row = $kid->_isConvertableTableRow( $options, $rowspan ); 
    846849            unless ($row) { 
    847850                return 0; 
     
    850853        } 
    851854        $kid = $kid->{next}; 
     855    } 
     856 
     857    if ( $rowspan and grep { $_ } @$rowspan ) { 
     858 
     859        # One or more cells span rows past the last row in the table. 
     860        # This is a defect in the HTML table which TML cannot represent. 
     861        return 0; 
    852862    } 
    853863    return 1; 
     
    865875} 
    866876 
    867 # probe down into a list item to determine if the 
     877# probe down into a table row to determine if the 
    868878# containing table can be converted to TML. 
    869879sub _isConvertableTableRow { 
    870     my ( $this, $options ) = @_; 
     880    my ( $this, $options, $rowspan ) = @_; 
    871881 
    872882    return 0 if ( $this->_isProtectedByAttrs() ); 
     
    876886    my $ignoreCols = 0; 
    877887    my $kid        = $this->{head}; 
     888    my $colIdx     = 0; 
     889    while ( $rowspan and $rowspan->[$colIdx] ) { 
     890        push @row, $WC::NBSP . '^' . $WC::NBSP; 
     891        $rowspan->[$colIdx]--; 
     892        $colIdx++; 
     893    } 
    878894    while ($kid) { 
    879895        if ( $kid->{tag} eq 'th' ) { 
     
    913929            } 
    914930            if ( $kid->{attrs}->{rowspan} && $kid->{attrs}->{rowspan} > 1 ) { 
    915                 return 0; 
     931                return 0 unless $rowspan; 
     932                $rowspan->[$colIdx] = $kid->{attrs}->{rowspan} - 1; 
    916933            } 
    917934        } 
     
    937954        # Pad to allow wikiwords to work 
    938955        push( @row, $text ); 
     956        $colIdx++; 
    939957        while ( $ignoreCols > 1 ) { 
     958            if ( $rowspan and $rowspan->[$colIdx] ) { 
     959 
     960                # rowspan and colspan into the same cell 
     961                return 0; 
     962            } 
    940963            push( @row, '' ); 
    941964            $ignoreCols--; 
     965            $colIdx++; 
     966        } 
     967        while ( $rowspan and $rowspan->[$colIdx] ) { 
     968            push @row, $WC::NBSP . '^' . $WC::NBSP; 
     969            $rowspan->[$colIdx]--; 
     970            $colIdx++; 
    942971        } 
    943972        $kid = $kid->{next}; 
     
    15651594        \@table ); 
    15661595 
    1567     my $maxrow = 0; 
    1568     my $row; 
    1569     foreach $row (@table) { 
    1570         my $rw = scalar(@$row); 
    1571         $maxrow = $rw if ( $rw > $maxrow ); 
    1572     } 
    1573     foreach $row (@table) { 
    1574         while ( scalar(@$row) < $maxrow ) { 
    1575             push( @$row, '' ); 
    1576         } 
    1577     } 
    15781596    my $text = $WC::CHECKn; 
    1579     foreach $row (@table) { 
     1597    foreach my $row (@table) { 
    15801598 
    15811599        # isConvertableTableRow has already formatted the cell 
  • trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/TML2HTML.pm

    r5503 r5573  
    115115    if ($content =~ /[$TT0$TT1$TT2]/o) { 
    116116        # There should never be any of these in the text at this point. 
    117         # If there are, then the conversion failed.  
     117        # If there are, then the conversion failed. 
    118118        die("Invalid characters in HTML after conversion") if $options->{dieOnError}; 
    119         # Encode the original TML as verbatim-style HTML,  
     119 
     120        # Encode the original TML as verbatim-style HTML, 
    120121        # so that the user has uncorrupted TML, at least. 
    121122        my $originalContent = $_[1]; 
     
    245246 
    246247# Lifted straight out of DevelopBranch Render.pm 
     248# Then modified to include TablePlugin's approach to table rendering 
    247249sub _getRenderedVersion { 
    248250    my ( $this, $text, $refs ) = @_; 
     
    342344    my $inList      = 0;         # True when within a list type 
    343345    my $inTable     = 0;         # True when within a table type 
     346    my %table       = (); 
    344347    my $inParagraph = 1;         # True when within a P 
    345348    my @result      = ('<p>'); 
     
    354357            $this->_addListItem( \@result, '', '', '' ) if $inList; 
    355358            $inList = 0; 
    356             unless ($inTable) { 
    357                 push( 
    358                     @result, 
    359                     CGI::start_table( 
    360                         { border => 1, cellpadding => 0, cellspacing => 1 } 
    361                     ) 
    362                 ); 
    363             } 
    364             push( @result, _emitTR($1) ); 
     359            push( @result, _processTableRow( $1, $inTable, \%table ) ); 
    365360            $inTable = 1; 
    366361            next; 
     
    368363 
    369364        if ($inTable) { 
    370             push( @result, CGI::end_table() ); 
     365            push( @result, _emitTable( \%table ) ); 
    371366            $inTable = 0; 
    372367        } 
     
    468463 
    469464    if ($inTable) { 
    470         push( @result, '</table>' ); 
     465        push( @result, _emitTable( \%table ) ); 
    471466    } 
    472467    elsif ($inList) { 
     
    529524 
    530525    return $text; 
     526} 
     527 
     528sub _processTableRow { 
     529 
     530    my ( $theRow, $inTable, $state ) = @_; 
     531    my @result; 
     532    my $firstRow = 0; 
     533    if ( !$inTable ) { 
     534 
     535        %$state = ( curTable => [], rowspan => [] ); 
     536        $firstRow = 1; 
     537    } 
     538 
     539    $theRow =~ s/\t/   /go;     # change tabs to space 
     540    $theRow =~ s/\s*$//o;       # remove trailing spaces 
     541    $theRow =~ s/^(\s*)\|//;    # Remove leading junk 
     542    my $pre = $1; 
     543 
     544    $theRow =~ 
     545      s/(\|\|+)/'colspan'.$Foswiki::TranslationToken.length($1)."\|"/geo 
     546      ;                         # calc COLSPAN 
     547    my $colCount = 0; 
     548    my @row      = (); 
     549    my $span     = 0; 
     550    my $value    = ''; 
     551 
     552    my $rowspanEnabled = Foswiki::Func::getContext()->{'TablePluginEnabled'}; 
     553 
     554    foreach ( split( /\|/, $theRow ) ) { 
     555        my $attr = {}; 
     556        $span = 1; 
     557        if (s/colspan$Foswiki::TranslationToken([0-9]+)//) { 
     558            $span = $1; 
     559            $attr->{colspan} = $span; 
     560        } 
     561        s/^\s+$/ &nbsp; /o; 
     562        my ( $left, $right ) = ( 0, 0 ); 
     563        if (/^(\s*)(.*?)(\s*)$/) { 
     564            $left  = length($1); 
     565            $_     = $2; 
     566            $right = length($3); 
     567        } 
     568        if ( $left == 1 && $right < 2 ) { 
     569 
     570            # Treat left=1 and right=0 like 1 and 1 - Item5220 
     571        } 
     572        elsif ( $left > $right ) { 
     573            $attr->{class} = 'align-right'; 
     574            $attr->{style} = 'text-align: right'; 
     575        } 
     576        elsif ( $left < $right ) { 
     577            $attr->{class} = 'align-left'; 
     578            $attr->{style} = 'text-align: left'; 
     579        } 
     580        elsif ( $left > 1 ) { 
     581            $attr->{class} = 'align-center'; 
     582            $attr->{style} = 'text-align: center'; 
     583        } 
     584 
     585        if (    $rowspanEnabled 
     586            and !$firstRow 
     587            and /^(\s|<[^>]*>)*\^(\s|<[^>]*>)*$/ ) 
     588        {    # row span above 
     589            $state->{rowspan}->[$colCount]++; 
     590            push @row, { text => $value, type => 'Y' }; 
     591        } 
     592        else { 
     593            for ( my $col = $colCount ; $col < ( $colCount + $span ) ; $col++ ) 
     594            { 
     595                if ( defined( $state->{rowspan}->[$col] ) 
     596                    && $state->{rowspan}->[$col] ) 
     597                { 
     598                    my $nRows = scalar( @{ $state->{curTable} } ); 
     599                    my $rspan = $state->{rowspan}->[$col] + 1; 
     600                    if ( $rspan > 1 ) { 
     601                        $state->{curTable}->[ $nRows - $rspan ][$col]->{attrs} 
     602                          ->{rowspan} = $rspan; 
     603                    } 
     604                    undef( $state->{rowspan}->[$col] ); 
     605                } 
     606            } 
     607 
     608            my $type = ''; 
     609            if (/^\s*\*(.*)\*\s*$/) { 
     610                $value = $1; 
     611                $type  = 'th'; 
     612            } 
     613            else { 
     614                if (/^\s*(.*?)\s*$/) {    # strip white spaces 
     615                    $_ = $1; 
     616                } 
     617                $value = $_; 
     618                $type  = 'td'; 
     619            } 
     620 
     621            $value = ' ' . $value if $value =~ /^(?:\*|==?|__?)[^\s]/; 
     622            $value = $value . ' ' if $value =~ /[^\s](?:\*|==?|__?)$/; 
     623 
     624            push @row, { text => $value, attrs => $attr, type => $type }; 
     625        } 
     626 
     627        while ( $span > 1 ) { 
     628            push @row, { text => $value, type => 'X' }; 
     629            $colCount++; 
     630            $span--; 
     631        } 
     632        $colCount++; 
     633    } 
     634    push @{ $state->{curTable} }, \@row; 
     635    push @{ $state->{pre} },      $pre; 
     636    return; 
     637} 
     638 
     639sub _emitTable { 
     640    my ($state) = @_; 
     641 
     642    my @result; 
     643    push( @result, 
     644        CGI::start_table( { border => 1, cellpadding => 0, cellspacing => 1 } ) 
     645    ); 
     646 
     647    #Flush out any remaining rowspans 
     648    for ( my $i = 0 ; $i < scalar( @{ $state->{rowspan} } ) ; $i++ ) { 
     649        if ( defined( $state->{rowspan}->[$i] ) && $state->{rowspan}->[$i] ) { 
     650            my $nRows = scalar( @{ $state->{curTable} } ); 
     651            my $rspan = $state->{rowspan}->[$i] + 1; 
     652            my $r     = $nRows - $rspan; 
     653            $state->{curTable}->[$r][$i]->{attrs} ||= {}; 
     654            if ( $rspan > 1 ) { 
     655                $state->{curTable}->[$r][$i]->{attrs}->{rowspan} = $rspan; 
     656            } 
     657        } 
     658    } 
     659 
     660    my $rowCount     = 0; 
     661    my $numberOfRows = scalar( @{ $state->{curTable} } ); 
     662 
     663    my @headerRowList = (); 
     664    my @bodyRowList   = (); 
     665 
     666    my $isPastHeaderRows = 0; 
     667 
     668    foreach my $row ( @{ $state->{curTable} } ) { 
     669        my $rowtext  = ''; 
     670        my $colCount = 0; 
     671 
     672        # keep track of header cells: if all cells are header cells, 
     673        # put the row in the thead section 
     674        my $headerCellCount = 0; 
     675        my $numberOfCols    = scalar(@$row); 
     676 
     677        foreach my $fcell (@$row) { 
     678 
     679            # check if cell exists 
     680            next if ( !$fcell || !$fcell->{type} ); 
     681 
     682            my $tableAnchor = ''; 
     683            next 
     684              if ( $fcell->{type} eq 'X' ) 
     685              ;    # data was there so sort could work with col spanning 
     686            my $type = $fcell->{type}; 
     687            my $cell = $fcell->{text}; 
     688            my $attr = $fcell->{attrs} || {}; 
     689 
     690            if ( $type eq 'th' ) { 
     691                $headerCellCount++; 
     692            } 
     693            else { 
     694                $type = 'td' unless $type eq 'Y'; 
     695            }      ###if( $type eq 'th' ) 
     696 
     697            $colCount++; 
     698            next if ( $type eq 'Y' ); 
     699            my $fn = 'CGI::' . $type; 
     700            no strict 'refs'; 
     701            $rowtext .= &$fn( $attr, " $cell " ); 
     702            use strict 'refs'; 
     703        }    # foreach my $fcell ( @$row ) 
     704 
     705        my $rowHTML = $state->{pre}->[$rowCount] . CGI::Tr($rowtext); 
     706 
     707        my $isHeaderRow = ( $headerCellCount == $colCount ); 
     708        if ( !$isHeaderRow ) { 
     709 
     710        # don't include non-adjacent header rows to the top block of header rows 
     711            $isPastHeaderRows = 1; 
     712        } 
     713 
     714        if ( $isHeaderRow && !$isPastHeaderRows ) { 
     715            push( @headerRowList, $rowHTML ); 
     716        } 
     717        else { 
     718            push @bodyRowList, $rowHTML; 
     719        } 
     720 
     721        $rowCount++; 
     722    }    # foreach my $row ( @curTable ) 
     723 
     724    push @result, @headerRowList, @bodyRowList; 
     725 
     726    push @result, CGI::end_table(); 
     727    return @result; 
    531728} 
    532729 
     
    561758sub _protectVerbatimChars { 
    562759    my $text = shift; 
    563     # $TT0, $TT1 and $TT2 are chr(0), chr(1) and chr(2), respectively.  
     760 
     761    # $TT0, $TT1 and $TT2 are chr(0), chr(1) and chr(2), respectively. 
    564762    # They are handled specially, elsewhere 
    565763    $text =~ s/([\003-\011\013-\037<&>'"])/'&#'.ord($1).';'/ges; 
  • trunk/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin/build.pl

    r3959 r5573  
    1515 
    1616# Build the target on the command line, or the default target 
    17 $build->build($build->{target}); 
     17$build->build( $build->{target} ); 
    1818 
  • trunk/WysiwygPlugin/test/unit/WysiwygPlugin/ExtendedTranslatorTests.pm

    r5240 r5573  
    3636# Bits for test type 
    3737# Fields in test records: 
    38 my $TML2HTML  = 1 << 0;        # test tml => html 
    39 my $HTML2TML  = 1 << 1;        # test html => finaltml (default tml) 
    40 my $ROUNDTRIP = 1 << 2;        # test tml => => finaltml 
     38my $TML2HTML      = 1 << 0;    # test tml => html 
     39my $HTML2TML      = 1 << 1;    # test html => finaltml (default tml) 
     40my $ROUNDTRIP     = 1 << 2;    # test tml => => finaltml 
    4141my $CANNOTWYSIWYG = 1 << 3;    # test that notWysiwygEditable returns true 
    4242                               #   and make the ROUNDTRIP test expect failure 
     
    6161# is "WysiwygEditable". 
    6262# 
    63 # Use CANNOTWYSIWYG without ROUNDTRIP *only* with an appropriate  
    64 # explanation. For example:  
     63# Use CANNOTWYSIWYG without ROUNDTRIP *only* with an appropriate 
     64# explanation. For example: 
    6565#   Can't ROUNDTRIP this TML because perl on the SMURF platform 
    6666#   automagically replaces all instances of 'blue' with 'beautiful'. 
     
    8585# Each testcase is a subhash with fields as follows: 
    8686# exec => $TML2HTML to test TML -> HTML, $HTML2TML to test HTML -> TML, 
    87 #   $ROUNDTRIP to test TML-> ->TML, $CANNOTWYSIWYG to test  
     87#   $ROUNDTRIP to test TML-> ->TML, $CANNOTWYSIWYG to test 
    8888#   notWysiwygEditable, all other bits are ignored. 
    8989#   They may be OR'd togoether to perform multiple tests. 
     
    102102my $data = [ 
    103103    { 
    104         exec => $TML2HTML | $ROUNDTRIP, 
    105         name => 'UnspecifiedCustomXmlTag', 
    106         setup => sub { 
    107             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     104        exec  => $TML2HTML | $ROUNDTRIP, 
     105        name  => 'UnspecifiedCustomXmlTag', 
     106        setup => sub { 
     107            $extraTML2HTMLOptions{xmltag} = 
     108              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    108109        }, 
    109110        html => '<p>' 
     
    122123        name  => 'DisabledCustomXmlTag', 
    123124        setup => sub { 
    124             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     125            $extraTML2HTMLOptions{xmltag} = 
     126              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    125127            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    126128                sub { 0 } ); 
     
    141143        name  => 'CustomXmlTag', 
    142144        setup => sub { 
    143             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     145            $extraTML2HTMLOptions{xmltag} = 
     146              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    144147            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    145148                sub { 1 } ); 
     
    155158        name  => 'CustomXmlTagCallbackChangesText', 
    156159        setup => sub { 
    157             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     160            $extraTML2HTMLOptions{xmltag} = 
     161              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    158162            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    159163                sub { $_[0] =~ s/some/different/; return 1; } ); 
     
    170174        name  => 'CustomXmlTagDefaultCallback', 
    171175        setup => sub { 
    172             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    173             Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag' ); 
     176            $extraTML2HTMLOptions{xmltag} = 
     177              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     178            Foswiki::Plugins::WysiwygPlugin::addXMLTag('customtag'); 
    174179        }, 
    175180        html => '<p>' 
     
    183188        name  => 'CustomXmlTagWithAttributes', 
    184189        setup => sub { 
    185             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     190            $extraTML2HTMLOptions{xmltag} = 
     191              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    186192            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    187193                sub { 1 } ); 
     
    201207        name  => 'NestedCustomXmlTagWithAttributes', 
    202208        setup => sub { 
    203             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     209            $extraTML2HTMLOptions{xmltag} = 
     210              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    204211            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    205212                sub { 1 } ); 
     
    226233    { 
    227234        exec => $CANNOTWYSIWYG, 
     235 
    228236        # Do not perform ROUNDTRIP on this TML, because ROUNDTRIP passes. 
    229         # The problem with this TML is that the special handling of  
    230         # <verbatim> in the conversion to HTML messes up the contents  
    231         # of this custom XML  tag, so that the HTML is not representative  
     237        # The problem with this TML is that the special handling of 
     238        # <verbatim> in the conversion to HTML messes up the contents 
     239        # of this custom XML  tag, so that the HTML is not representative 
    232240        # of the TML in terms of intellectual content. 
    233         name => 'VerbatimInsideDot', 
    234         setup => sub { 
    235             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    236             Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'dot', 
    237                 sub { 1 } ); 
     241        name  => 'VerbatimInsideDot', 
     242        setup => sub { 
     243            $extraTML2HTMLOptions{xmltag} = 
     244              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     245            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'dot', sub { 1 } ); 
    238246        }, 
    239247        tml => <<'DOT', 
     
    249257    }, 
    250258    { 
    251         exec => $TML2HTML | $ROUNDTRIP, 
    252         name => 'CustomtagInsideSticky', 
    253         setup => sub { 
    254             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     259        exec  => $TML2HTML | $ROUNDTRIP, 
     260        name  => 'CustomtagInsideSticky', 
     261        setup => sub { 
     262            $extraTML2HTMLOptions{xmltag} = 
     263              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    255264            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    256265                sub { 1 } ); 
    257266        }, 
    258         tml => "<sticky><customtag>this & that\n >   the other </customtag></sticky>", 
     267        tml => 
     268"<sticky><customtag>this & that\n >   the other </customtag></sticky>", 
    259269        html => '<p>' 
    260270          . '<div class="WYSIWYG_STICKY">' 
     
    262272          . 'this&nbsp;&amp;&nbsp;that<br />&nbsp;&gt;&nbsp;&nbsp;&nbsp;the&nbsp;other&nbsp;' 
    263273          . '&lt;/customtag&gt;' 
    264           . '</div>' 
    265           . '</p>' 
    266     }, 
    267     { 
    268         exec => $ROUNDTRIP | $CANNOTWYSIWYG, #SMELL: fix this case 
    269         name => 'StickyInsideCustomtag', 
    270         setup => sub { 
    271             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     274          . '</div>' . '</p>' 
     275    }, 
     276    { 
     277        exec  => $ROUNDTRIP | $CANNOTWYSIWYG,    #SMELL: fix this case 
     278        name  => 'StickyInsideCustomtag', 
     279        setup => sub { 
     280            $extraTML2HTMLOptions{xmltag} = 
     281              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    272282            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    273283                sub { 1 } ); 
    274284        }, 
    275         tml => "<customtag>this <sticky>& that\n >   the</sticky> other </customtag>", 
     285        tml => 
     286"<customtag>this <sticky>& that\n >   the</sticky> other </customtag>", 
    276287        html => '<p>' 
    277288          . $protecton 
     
    283294          . '&nbsp;other&nbsp;' 
    284295          . '&lt;/customtag&gt;' 
    285           . $protectoff 
    286           . '</p>' 
    287     }, 
    288     { 
    289         exec => $TML2HTML | $ROUNDTRIP, 
    290         name => 'StickyInsideUnspecifiedCustomtag', 
    291         setup => sub { 
    292             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    293         }, 
    294         tml => "<customtag>this <sticky>& that\n >   the</sticky> other </customtag>", 
     296          . $protectoff . '</p>' 
     297    }, 
     298    { 
     299        exec  => $TML2HTML | $ROUNDTRIP, 
     300        name  => 'StickyInsideUnspecifiedCustomtag', 
     301        setup => sub { 
     302            $extraTML2HTMLOptions{xmltag} = 
     303              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     304        }, 
     305        tml => 
     306"<customtag>this <sticky>& that\n >   the</sticky> other </customtag>", 
    295307        html => '<p>' 
    296308          . $protecton 
    297309          . '&lt;customtag&gt;' 
    298           . $protectoff 
    299           . 'this' 
     310          . $protectoff . 'this' 
    300311          . '<div class="WYSIWYG_STICKY">' 
    301312          . '&amp;&nbsp;that<br />&nbsp;&gt;&nbsp;&nbsp;&nbsp;the' 
    302           . '</div>' 
    303           . 'other' 
     313          . '</div>' . 'other' 
    304314          . $protecton 
    305315          . '&lt;/customtag&gt;' 
    306           . $protectoff 
    307           . '</p>' 
    308     }, 
    309     { 
    310         exec => $ROUNDTRIP, 
    311         name => 'UnspecifiedCustomtagInsideSticky', 
    312         setup => sub { 
    313             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    314         }, 
    315         tml => "<sticky><customtag>this & that\n >   the other </customtag></sticky>" 
    316     }, 
    317     { 
    318         exec => $TML2HTML | $ROUNDTRIP, 
    319         name => 'CustomtagInsideLiteral', 
    320         setup => sub { 
    321             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     316          . $protectoff . '</p>' 
     317    }, 
     318    { 
     319        exec  => $ROUNDTRIP, 
     320        name  => 'UnspecifiedCustomtagInsideSticky', 
     321        setup => sub { 
     322            $extraTML2HTMLOptions{xmltag} = 
     323              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     324        }, 
     325        tml => 
     326          "<sticky><customtag>this & that\n >   the other </customtag></sticky>" 
     327    }, 
     328    { 
     329        exec  => $TML2HTML | $ROUNDTRIP, 
     330        name  => 'CustomtagInsideLiteral', 
     331        setup => sub { 
     332            $extraTML2HTMLOptions{xmltag} = 
     333              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    322334            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    323335                sub { 1 } ); 
    324336        }, 
    325         tml => '<literal><customtag>this & that >   the other </customtag></literal>', 
     337        tml => 
     338'<literal><customtag>this & that >   the other </customtag></literal>', 
    326339        html => '<p>' 
    327340          . '<div class="WYSIWYG_LITERAL">' 
    328341          . '<customtag>this & that >   the other </customtag>' 
    329           . '</div>' 
    330           . '</p>' 
    331     }, 
    332     { 
    333         exec => $TML2HTML | $ROUNDTRIP, 
    334         name => 'UnspecifiedCustomtagInsideLiteral', 
    335         setup => sub { 
    336             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    337         }, 
    338         tml => '<literal><customtag>this & that >   the other </customtag></literal>', 
     342          . '</div>' . '</p>' 
     343    }, 
     344    { 
     345        exec  => $TML2HTML | $ROUNDTRIP, 
     346        name  => 'UnspecifiedCustomtagInsideLiteral', 
     347        setup => sub { 
     348            $extraTML2HTMLOptions{xmltag} = 
     349              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     350        }, 
     351        tml => 
     352'<literal><customtag>this & that >   the other </customtag></literal>', 
    339353        html => '<p>' 
    340354          . '<div class="WYSIWYG_LITERAL">' 
    341355          . '<customtag>this & that >   the other </customtag>' 
    342           . '</div>' 
    343           . '</p>' 
    344     }, 
    345     { 
    346         exec => $ROUNDTRIP | $CANNOTWYSIWYG, #SMELL: Fix this case 
    347         name => 'LiteralInsideCustomtag', 
    348         setup => sub { 
    349             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     356          . '</div>' . '</p>' 
     357    }, 
     358    { 
     359        exec  => $ROUNDTRIP | $CANNOTWYSIWYG,    #SMELL: Fix this case 
     360        name  => 'LiteralInsideCustomtag', 
     361        setup => sub { 
     362            $extraTML2HTMLOptions{xmltag} = 
     363              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    350364            Foswiki::Plugins::WysiwygPlugin::addXMLTag( 'customtag', 
    351365                sub { 1 } ); 
    352366        }, 
    353         tml => '<customtag>this <literal>& that > the</literal> other </customtag>', 
     367        tml => 
     368          '<customtag>this <literal>& that > the</literal> other </customtag>', 
    354369        html => '<p>' 
    355370          . '<div class="WYSIWYG_LITERAL">' 
    356371          . '<customtag>this & that > the other </customtag>' 
    357           . '</div>' 
    358           . '</p>' 
    359     }, 
    360     { 
    361         exec => $TML2HTML | $ROUNDTRIP, 
    362         name => 'LiteralInsideUnspecifiedCustomtag', 
    363         setup => sub { 
    364             $extraTML2HTMLOptions{xmltag} = \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
    365         }, 
    366         tml => '<customtag>this <literal>& that > the</literal> other </customtag>', 
     372          . '</div>' . '</p>' 
     373    }, 
     374    { 
     375        exec  => $TML2HTML | $ROUNDTRIP, 
     376        name  => 'LiteralInsideUnspecifiedCustomtag', 
     377        setup => sub { 
     378            $extraTML2HTMLOptions{xmltag} = 
     379              \%Foswiki::Plugins::WysiwygPlugin::xmltag; 
     380        }, 
     381        tml => 
     382          '<customtag>this <literal>& that > the</literal> other </customtag>', 
    367383        html => '<p>' 
    368384          . $protecton 
    369385          . '&lt;customtag&gt;' 
    370           . $protectoff 
    371           . 'this' 
     386          . $protectoff . 'this' 
    372387          . '<div class="WYSIWYG_LITERAL">' 
    373388          . '& that > the' 
    374           . '</div>' 
    375           .'other' 
     389          . '</div>' . 'other' 
    376390          . $protecton 
    377391          . '&lt;/customtag&gt;' 
    378           . $protectoff 
    379           . '</p>' 
    380     }, 
    381     { 
    382         # There will probably always be some markup that WysiwygPlugin cannot convert, 
    383         # but it is not always easy to say what that markup is. 
    384         # This test case checks the protection of unconvertable text 
    385         # by using valid markup and forcing the conversion to fail. 
     392          . $protectoff . '</p>' 
     393    }, 
     394    { 
     395 
     396  # There will probably always be some markup that WysiwygPlugin cannot convert, 
     397  # but it is not always easy to say what that markup is. 
     398  # This test case checks the protection of unconvertable text 
     399  # by using valid markup and forcing the conversion to fail. 
     400        exec  => $TML2HTML | $ROUNDTRIP, 
     401        name  => 'UnconvertableTextIsProtected', 
     402        setup => sub { 
     403 
     404       # Disable "dieOnError" to test the "protect unconvertable text" behaviour 
     405       # which can be exercised via the REST handler 
     406            $extraTML2HTMLOptions{dieOnError} = 0; 
     407 
     408# Override the standard expansion function to hack in an illegal character to force the conversion to fail 
     409            $extraTML2HTMLOptions{expandVarsInURL} = sub { return "\0"; }; 
     410        }, 
     411        tml => '<img src="%PUBURLPATH%">', 
     412        html => 
     413'<div class="WYSIWYG_PROTECTED">&lt;img&nbsp;src="%PUBURLPATH%"&gt;</div>' 
     414    }, 
     415    { 
     416        exec => $HTML2TML | $ROUNDTRIP, 
     417        name => 'TableWithRowSpan_NoTablePlugin', 
     418        setup => 
     419          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     420        html => <<HTML, 
     421<table cellspacing="1" cellpadding="0" border="1"> 
     422<tr><td rowspan="2">A</td><td rowspan="3">B</td><td>X</td></tr> 
     423<tr><td rowspan="2">C</td></tr> 
     424<tr><td>M</td></tr> 
     425</table> 
     426HTML 
     427        tml => <<TML, 
     428<table cellspacing="1" cellpadding="0" border="1"> <tr><td rowspan="2">A</td><td rowspan="3">B</td><td>X</td></tr> <tr><td rowspan="2">C</td></tr> <tr><td>M</td></tr> </table> 
     429TML 
     430    }, 
     431    { 
    386432        exec => $TML2HTML | $ROUNDTRIP, 
    387         name => 'UnconvertableTextIsProtected', 
    388         setup => sub { 
    389             # Disable "dieOnError" to test the "protect unconvertable text" behaviour 
    390             # which can be exercised via the REST handler 
    391             $extraTML2HTMLOptions{dieOnError} = 0; 
    392  
    393             # Override the standard expansion function to hack in an illegal character to force the conversion to fail 
    394             $extraTML2HTMLOptions{expandVarsInURL} = sub { return "\0"; }; 
    395         }, 
    396         tml => '<img src="%PUBURLPATH%">', 
    397         html => '<div class="WYSIWYG_PROTECTED">&lt;img&nbsp;src="%PUBURLPATH%"&gt;</div>' 
     433        name => 'simpleTable_NoTablePlugin', 
     434        setup => 
     435          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     436        html => <<'HERE', 
     437<p> 
     438Before 
     439</p> 
     440<table border="1" cellpadding="0" cellspacing="1"><tr><th>L</th><th>C</th><th>R</th></tr><tr><td> A2</td><td style="text-align: center" class="align-center"> 2</td><td style="text-align: right" class="align-right"> 2</td></tr><tr><td> A3</td><td style="text-align: center" class="align-center"> 3</td><td style="text-align: left" class="align-left"> 3</td></tr><tr><td> A4-6</td><td> four</td><td> four</td></tr><tr><td>^</td><td> five</td><td> five</td></tr></table><p /><table border="1" cellpadding="0" cellspacing="1"><tr><td>^</td><td> six</td><td> six</td></tr></table> 
     441After 
     442HERE 
     443        tml => <<'HERE', 
     444Before 
     445| *L* | *C* | *R* | 
     446| A2 |  2  |  2 | 
     447| A3 |  3  | 3  | 
     448| A4-6 | four | four | 
     449|^| five | five | 
     450 
     451|^| six | six | 
     452After 
     453 
     454HERE 
     455        finaltml => <<'HERE', 
     456Before 
     457| *L* | *C* | *R* | 
     458| A2 |  2  |  2 | 
     459| A3 |  3  | 3  | 
     460| A4-6 | four | four | 
     461| ^ | five | five | 
     462 
     463| ^ | six | six | 
     464After 
     465HERE 
     466    }, 
     467    { 
     468        exec => $HTML2TML, 
     469        name => 'ttClassInTable_NoTablePlugin', 
     470        setup => 
     471          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     472        html => '<table><tr><td class="WYSIWYG_TT">Code</td></tr></table>', 
     473        tml  => '| =Code= |' 
     474    }, 
     475    { 
     476        exec => $TML2HTML | $ROUNDTRIP, 
     477        name => 'tmlInTable_NoTablePlugin', 
     478        setup => 
     479          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     480        html => <<'BLAH', 
     481<table cellspacing="1" cellpadding="0" border="1"> 
     482<tr><td> <span class="WYSIWYG_TT">Code</span> </td></tr> 
     483<tr><td> <span class="WYSIWYG_TT">code</span> at start</td></tr> 
     484<tr><td>ends with <span class="WYSIWYG_TT">code</span> </td></tr> 
     485 
     486<tr><td> <b><span class="WYSIWYG_TT">Code</span></b> </td></tr> 
     487<tr><td> <b><span class="WYSIWYG_TT">code</span></b> at start</td></tr> 
     488<tr><td>ends with <b><span class="WYSIWYG_TT">code</span></b> </td></tr> 
     489 
     490<tr><td> <i>Emphasis</i> </td></tr> 
     491<tr><td> <i>emphasis</i> at start</td></tr> 
     492<tr><td>ends with <i>emphasis</i> </td></tr> 
     493 
     494<tr><td> <b><i>Emphasis</i></b> </td></tr> 
     495<tr><td> <b><i>emphasis</i></b> at start</td></tr> 
     496<tr><td>ends with <b><i>emphasis</i></b> </td></tr> 
     497 
     498<tr><td> <b>bold</b> at start</td></tr> 
     499<tr><td>ends with <b>bold</b> </td></tr> 
     500</table> 
     501BLAH 
     502        tml => <<'BLAH', 
     503| =Code= | 
     504| =code= at start | 
     505| ends with =code= | 
     506| ==Code== | 
     507| ==code== at start | 
     508| ends with ==code== | 
     509| _Emphasis_ | 
     510| _emphasis_ at start | 
     511| ends with _emphasis_ | 
     512| __Emphasis__ | 
     513| __emphasis__ at start | 
     514| ends with __emphasis__ | 
     515| *bold* at start | 
     516| ends with *bold* | 
     517BLAH 
     518    }, 
     519    { 
     520        exec => $HTML2TML, 
     521        name => 'kupuTable_NoTablePlugin', 
     522        setup => 
     523          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     524        html => 
     525'<table cellspacing="0" cellpadding="8" border="1" class="plain" _moz_resizing="true"> 
     526<tbody> 
     527<tr>a0<td>a1</td><td>a2</td><td>a3</td></tr> 
     528<tr>b0<td colspan="2">b1</td><td>b3</td></tr> 
     529<tr>c0<td>c1</td><td>c2</td><td>c3</td></tr> 
     530</tbody> 
     531</table>', 
     532        tml => '| a1 | a2 | a3 | 
     533| b1 || b3 | 
     534| c1 | c2 | c3 | 
     535', 
     536    }, 
     537    { 
     538        exec => $TML2HTML | $ROUNDTRIP, 
     539        name => 'tableWithColSpans_NoTablePlugin', 
     540        setup => 
     541          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     542        html => '<p>abcd 
     543</p> 
     544<table cellspacing="1" cellpadding="0" border="1"> 
     545<tr><td colspan="2">efg</td><td>&nbsp;</td></tr> 
     546<tr><td colspan="3"></td></tr></table> 
     547hijk', 
     548        tml => 'abcd 
     549| efg || | 
     550|||| 
     551hijk', 
     552        finaltml => 'abcd 
     553| efg || | 
     554| ||| 
     555hijk', 
     556    }, 
     557    { 
     558        exec => $ROUNDTRIP, 
     559        name => 'Item4410_NoTablePlugin', 
     560        setup => 
     561          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     562        tml => <<'HERE', 
     563   * x 
     564| Y | 
     565HERE 
     566        html => 
     567'<ul><li>x</li></ul><table cellspacing="1" cellpadding="0" border="1"><tr><td>Y</td></tr></table>', 
     568    }, 
     569    { 
     570        exec => $HTML2TML, 
     571        name => 'tableInnaBun_NoTablePlugin', 
     572        setup => 
     573          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     574        html => <<'JUNK', 
     575<ul> 
     576<li> List item</li><li><table><tbody><tr><td>&nbsp;11</td><td>&nbsp;21</td></tr><tr><td>12&nbsp;</td><td>&nbsp;22</td></tr></tbody></table></li><li>crap</li> 
     577</ul> 
     578JUNK 
     579        tml => <<JUNX, 
     580   * List item 
     581   * <table><tbody><tr><td> 11</td><td> 21</td></tr><tr><td>12 </td><td> 22</td></tr></tbody></table> 
     582   * crap 
     583JUNX 
     584    }, 
     585    { 
     586        exec => $TML2HTML | $HTML2TML, 
     587        name => 'Item4700_NoTablePlugin', 
     588        setup => 
     589          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     590        tml => <<EXPT, 
     591| ex | per | iment | 
     592| exper | iment || 
     593| expe || riment | 
     594|| exper | iment | 
     595EXPT 
     596        finaltml => <<EXPT, 
     597| ex | per | iment | 
     598| exper | iment || 
     599| expe || riment | 
     600| | exper | iment | 
     601EXPT 
     602        html => <<HEXPT, 
     603<table cellspacing="1" cellpadding="0" border="1"> 
     604<tr><td>ex</td><td>per</td><td>iment</td></tr> 
     605<tr><td>exper</td><td colspan="2">iment</td></tr> 
     606<tr><td colspan="2">expe</td><td>riment</td></tr> 
     607<tr><td></td><td>exper</td><td>iment</td></tr> 
     608</table> 
     609HEXPT 
     610    }, 
     611    { 
     612        exec => $ROUNDTRIP, 
     613        name => 'Item4700_2_NoTablePlugin', 
     614        setup => 
     615          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     616        tml => <<EXPT, 
     617| ex | per | iment | 
     618| exper | iment || 
     619| expe || riment | 
     620| | exper | iment | 
     621EXPT 
     622        html => <<HEXPT, 
     623<table cellspacing="1" cellpadding="0" border="1"> 
     624<tr><td>ex</td><td>per</td><td>iment</td></tr> 
     625<tr><td>exper</td><td colspan="2">iment</td></tr> 
     626<tr><td colspan="2">expe</td><td>riment</td></tr> 
     627<tr><td></td><td>exper</td><td>iment</td></tr> 
     628</table> 
     629HEXPT 
     630    }, 
     631    { 
     632        name => 'Item4855_NoTablePlugin', 
     633        setup => 
     634          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     635        exec => $TML2HTML, 
     636        tml  => <<HERE, 
     637| [[LegacyTopic1]] | Main.SomeGuy | 
     638%TABLESEP% 
     639%SEARCH{"legacy" nonoise="on" format="| [[\$topic]] | [[\$wikiname]] |"}% 
     640HERE 
     641        html => <<THERE, 
     642<table cellspacing="1" cellpadding="0" border="1"> 
     643<tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td><span class="WYSIWYG_LINK">Main.SomeGuy</span></td></tr> 
     644</table> 
     645<span class="WYSIWYG_PROTECTED"><br />%TABLESEP%</span> 
     646<span class="WYSIWYG_PROTECTED"><br />%SEARCH{"legacy" nonoise="on" format="| [[\$topic]] | [[\$wikiname]] |"}%</span> 
     647THERE 
     648    }, 
     649    { 
     650        name => 'Item1798_NoTablePlugin', 
     651        setup => 
     652          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     653        exec => $ROUNDTRIP | $TML2HTML, 
     654        tml  => <<HERE, 
     655| [[LegacyTopic1]] | Main.SomeGuy | 
     656%SEARCH{"legacy" nonoise="on" format="| [[\$topic]] | [[\$wikiname]] |"}% 
     657HERE 
     658        html => <<THERE, 
     659<table cellspacing="1" cellpadding="0" border="1"> 
     660<tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td><span class="WYSIWYG_LINK">Main.SomeGuy</span></td></tr> 
     661</table> 
     662<span class="WYSIWYG_PROTECTED"><br />%SEARCH{"legacy" nonoise="on" format="| [[\$topic]] | [[\$wikiname]] |"}%</span> 
     663THERE 
     664    }, 
     665    { 
     666        exec => $HTML2TML | $ROUNDTRIP, 
     667        name => 'colorClassInTable_NoTablePlugin', 
     668        setup => 
     669          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     670        html => <<'BLAH', 
     671<table> 
     672<tr><th class="WYSIWYG_COLOR" style="color:#FF0000;">Red Heading</th></tr> 
     673<tr><td class="WYSIWYG_COLOR" style="color:#FF0000;">Red herring</td></tr> 
     674</table> 
     675BLAH 
     676        tml => <<'BLAH', 
     677| *%RED%Red Heading%ENDCOLOR%* | 
     678| %RED%Red herring%ENDCOLOR% | 
     679BLAH 
     680    }, 
     681    { 
     682        exec => $HTML2TML | $ROUNDTRIP, 
     683        name => 'colorAndTtClassInTable_NoTablePlugin', 
     684        setup => 
     685          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     686        html => <<'BLAH', 
     687<table> 
     688<tr><th class="WYSIWYG_COLOR WYSIWYG_TT" style="color:#FF0000;">Redder code</th></tr> 
     689<tr><td class="WYSIWYG_COLOR WYSIWYG_TT" style="color:#FF0000;">Red code</td></tr> 
     690</table> 
     691BLAH 
     692        tml => <<'BLAH', 
     693| *%RED% =Redder code= %ENDCOLOR%* | 
     694| %RED% =Red code= %ENDCOLOR% | 
     695BLAH 
     696    }, 
     697    { 
     698        name => 'Item4969_NoTablePlugin', 
     699        setup => 
     700          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     701        exec => $HTML2TML, 
     702        html => <<HERE, 
     703<table cellspacing="1" cellpadding="0" border="1"> 
     704<tr><td>table element with a <hr /> horizontal rule</td></tr> 
     705</table> 
     706Mad Fish 
     707HERE 
     708        tml => '| table element with a <hr /> horizontal rule | 
     709Mad Fish', 
     710    }, 
     711    { 
     712        name => 'Item5076_NoTablePlugin', 
     713        setup => 
     714          sub { Foswiki::Func::getContext()->{'TablePluginEnabled'} = 0; }, 
     715        exec => $HTML2TML, 
     716        html => <<HERE, 
     717<table border="0"><tbody><tr><td><h2>Argh</h2><ul><li>Ergh&nbsp;</li></ul></td><td>&nbsp;</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr></tbody></table> 
     718HERE 
     719        tml => '<table border="0"><tbody><tr><td> 
     720---++ Argh 
     721   * Ergh  
     722</td><td> </td></tr><tr><td> </td><td> </td></tr></tbody></table>', 
    398723    }, 
    399724]; 
     
    409734            my $fn = 'ExtendedTranslatorTests::testTML2HTML_' . $datum->{name}; 
    410735            no strict 'refs'; 
    411             *$fn = sub {  
    412                 my $this = shift;  
    413                 $this->testSpecificSetup($datum);  
    414                 $this->compareTML_HTML($datum);  
     736            *$fn = sub { 
     737                my $this = shift; 
     738                $this->testSpecificSetup($datum); 
     739                $this->compareTML_HTML($datum); 
    415740                $this->testSpecificCleanup($datum); 
    416741            }; 
     
    420745            my $fn = 'ExtendedTranslatorTests::testHTML2TML_' . $datum->{name}; 
    421746            no strict 'refs'; 
    422             *$fn = sub {  
     747            *$fn = sub { 
    423748                my $this = shift; 
    424                 $this->testSpecificSetup($datum);  
     749                $this->testSpecificSetup($datum); 
    425750                $this->compareHTML_TML($datum); 
    426751                $this->testSpecificCleanup($datum); 
     
    433758            *$fn = sub { 
    434759                my $this = shift; 
    435                 $this->testSpecificSetup($datum);  
     760                $this->testSpecificSetup($datum); 
    436761                $this->compareRoundTrip($datum); 
    437762                $this->testSpecificCleanup($datum); 
     
    442767            my $fn = 'TranslatorTests::testCANNOTWYSIWYG_' . $datum->{name}; 
    443768            no strict 'refs'; 
    444             *$fn = sub {  
     769            *$fn = sub { 
    445770                my $this = shift; 
    446                 $this->testSpecificSetup($datum);  
     771                $this->testSpecificSetup($datum); 
    447772                $this->compareNotWysiwygEditable($datum); 
    448773                $this->testSpecificCleanup($datum); 
     
    455780sub testSpecificSetup { 
    456781    my ( $this, $args ) = @_; 
     782 
    457783    # Reset the extendable parts of WysiwygPlugin 
    458784    %Foswiki::Plugins::WysiwygPlugin::xmltag       = (); 
     
    474800} 
    475801 
    476 sub TML_HTMLconverterOptions 
    477 { 
    478     my $this = shift; 
     802sub TML_HTMLconverterOptions { 
     803    my $this    = shift; 
    479804    my $options = $this->SUPER::TML_HTMLconverterOptions(@_); 
    480     for my $extraOptionName (keys %extraTML2HTMLOptions) { 
     805    for my $extraOptionName ( keys %extraTML2HTMLOptions ) { 
    481806        $options->{$extraOptionName} = $extraTML2HTMLOptions{$extraOptionName}; 
    482807    } 
  • trunk/WysiwygPlugin/test/unit/WysiwygPlugin/TranslatorTests.pm

    r5503 r5573  
    3636# Bits for test type 
    3737# Fields in test records: 
    38 my $TML2HTML  = 1 << 0;        # test tml => html 
    39 my $HTML2TML  = 1 << 1;        # test html => finaltml (default tml) 
    40 my $ROUNDTRIP = 1 << 2;        # test tml => => finaltml 
     38my $TML2HTML      = 1 << 0;    # test tml => html 
     39my $HTML2TML      = 1 << 1;    # test html => finaltml (default tml) 
     40my $ROUNDTRIP     = 1 << 2;    # test tml => => finaltml 
    4141my $CANNOTWYSIWYG = 1 << 3;    # test that notWysiwygEditable returns true 
    4242                               #   and make the ROUNDTRIP test expect failure 
     
    6161# is "WysiwygEditable". 
    6262# 
    63 # Use CANNOTWYSIWYG without ROUNDTRIP *only* with an appropriate  
    64 # explanation. For example:  
     63# Use CANNOTWYSIWYG without ROUNDTRIP *only* with an appropriate 
     64# explanation. For example: 
    6565#   Can't ROUNDTRIP this TML because perl on the SMURF platform 
    6666#   automagically replaces all instances of 'blue' with 'beautiful'. 
     
    8282# Each testcase is a subhash with fields as follows: 
    8383# exec => $TML2HTML to test TML -> HTML, $HTML2TML to test HTML -> TML, 
    84 #   $ROUNDTRIP to test TML-> ->TML, $CANNOTWYSIWYG to test  
     84#   $ROUNDTRIP to test TML-> ->TML, $CANNOTWYSIWYG to test 
    8585#   notWysiwygEditable, all other bits are ignored. 
    8686#   They may be OR'd togoether to perform multiple tests. 
     
    410410<div align="center">TEST Centered text.</div> 
    411411HERE 
    412         tml  => <<'HERE', 
     412        tml => <<'HERE', 
    413413<center>Center Text</center><br /> <div style="text-align:center">TEST Centered text.</div>  
    414414 
     
    425425HERE 
    426426    }, 
    427  
    428  
    429427 
    430428    { 
     
    16231621    }, 
    16241622    { 
     1623        exec => $TML2HTML | $ROUNDTRIP, 
     1624        name => 'RowSpan1', 
     1625        tml  => <<EXPT, 
     1626| A | B | 
     1627| C | ^ | 
     1628EXPT 
     1629        html => <<HEXPT, 
     1630<table border="1" cellpadding="0" cellspacing="1"> 
     1631<tr><td>A</td><td rowspan="2">B</td></tr> 
     1632<tr><td>C</td></tr> 
     1633</table> 
     1634HEXPT 
     1635    }, 
     1636    { 
     1637        exec => $TML2HTML | $ROUNDTRIP, 
     1638        name => 'RowSpan2', 
     1639        tml  => <<EXPT, 
     1640| A | B | 
     1641| ^ | C | 
     1642EXPT 
     1643        html => <<HEXPT, 
     1644<table border="1" cellpadding="0" cellspacing="1"> 
     1645<tr><td rowspan="2">A</td><td>B</td></tr> 
     1646<tr><td>C</td></tr> 
     1647</table> 
     1648HEXPT 
     1649    }, 
     1650    { 
     1651        exec => $TML2HTML | $ROUNDTRIP, 
     1652        name => 'RowSpan3', 
     1653        tml  => <<EXPT, 
     1654| A | B | X | 
     1655| ^ | ^ | C | 
     1656EXPT 
     1657        html => <<HEXPT, 
     1658<table border="1" cellpadding="0" cellspacing="1"> 
     1659<tr><td rowspan="2">A</td><td rowspan="2">B</td><td>X</td></tr> 
     1660<tr><td>C</td></tr> 
     1661</table> 
     1662HEXPT 
     1663    }, 
     1664    { 
     1665        exec => $TML2HTML | $ROUNDTRIP, 
     1666        name => 'RowSpan4', 
     1667        tml  => <<EXPT, 
     1668| A | B | X | 
     1669| ^ | ^ | C | 
     1670| M | ^ | ^ | 
     1671EXPT 
     1672        html => <<HEXPT, 
     1673<table border="1" cellpadding="0" cellspacing="1"> 
     1674<tr><td rowspan="2">A</td><td rowspan="3">B</td><td>X</td></tr> 
     1675<tr><td rowspan="2">C</td></tr> 
     1676<tr><td>M</td></tr> 
     1677</table> 
     1678HEXPT 
     1679    }, 
     1680    { 
     1681        exec => $TML2HTML | $ROUNDTRIP, 
     1682        name => 'RowSpan5', 
     1683        tml  => <<EXPT, 
     1684| A | B | X | 
     1685| ^ | ^ | C | 
     1686| M | ^ | 
     1687EXPT 
     1688        html => <<HEXPT, 
     1689<table border="1" cellpadding="0" cellspacing="1"> 
     1690<tr><td rowspan="2">A</td><td rowspan="3">B</td><td>X</td></tr> 
     1691<tr><td>C</td></tr> 
     1692<tr><td>M</td></tr> 
     1693</table> 
     1694HEXPT 
     1695        DISABLEDfinaltml => <<FEXPT, 
     1696| A | B | X | 
     1697| ^ | ^ | C | 
     1698| M | ^ | | 
     1699FEXPT 
     1700    }, 
     1701    { 
     1702        exec => $TML2HTML | $ROUNDTRIP, 
     1703        name => 'mergedRowsAndColumnsCentre', 
     1704        tml  => <<EXPT, 
     1705| A1 | A2 | A3 | A4 | 
     1706| B1 | X || B4 | 
     1707| C1 | ^ | C4 | 
     1708| D1 | D2 | D3 | D4 | 
     1709EXPT 
     1710        html => <<HEXPT, 
     1711<table border="1" cellpadding="0" cellspacing="1"> 
     1712<tr><td>A1</td><td>A2</td><td>A3</td><td>A4</td></tr> 
     1713<tr><td>B1</td><td rowspan="2" colspan="2">X</td><td>B4</td></tr> 
     1714<tr><td>C1</td><td>C4</td></tr> 
     1715<tr><td>D1</td><td>D2</td><td>D3</td><td>D4</td></tr> 
     1716</table> 
     1717HEXPT 
     1718    }, 
     1719    { 
     1720        exec => $TML2HTML | $ROUNDTRIP, 
     1721        name => 'mergedRowsAndColumnsTopLeft', 
     1722        tml  => <<EXPT, 
     1723| X || A3 | 
     1724| ^ | B3 | 
     1725| C1 | C2 | C3 | 
     1726EXPT 
     1727        html => <<HEXPT, 
     1728<table border="1" cellpadding="0" cellspacing="1"> 
     1729<tr><td rowspan="2" colspan="2">X</td><td>A3</td></tr> 
     1730<tr><td>B3</td></tr> 
     1731<tr><td>C1</td><td>C2</td><td>C3</td></tr> 
     1732</table> 
     1733HEXPT 
     1734    }, 
     1735    { 
     1736        exec => $TML2HTML | $ROUNDTRIP, 
     1737        name => 'mergedRowsAndColumnsTopRight', 
     1738        tml  => <<EXPT, 
     1739| A1 | X || 
     1740| B1 | ^ | 
     1741| C1 | C2 | C3 | 
     1742EXPT 
     1743        html => <<HEXPT, 
     1744<table border="1" cellpadding="0" cellspacing="1"> 
     1745<tr><td>A1</td><td rowspan="2" colspan="2">X</td></tr> 
     1746<tr><td>B1</td></tr> 
     1747<tr><td>C1</td><td>C2</td><td>C3</td></tr> 
     1748</table> 
     1749HEXPT 
     1750    }, 
     1751    { 
     1752        exec => $TML2HTML | $ROUNDTRIP, 
     1753        name => 'mergedRowsAndColumnsBottomLeft', 
     1754        tml  => <<EXPT, 
     1755| A1 | A2 | A3 | 
     1756| X || B3 | 
     1757| ^ | C3 | 
     1758EXPT 
     1759        html => <<HEXPT, 
     1760<table border="1" cellpadding="0" cellspacing="1"> 
     1761<tr><td>A1</td><td>A2</td><td>A3</td></tr> 
     1762<tr><td rowspan="2" colspan="2">X</td><td>B3</td></tr> 
     1763<tr><td>C3</td></tr> 
     1764</table> 
     1765HEXPT 
     1766    }, 
     1767    { 
     1768        exec => $TML2HTML | $ROUNDTRIP, 
     1769        name => 'mergedRowsAndColumnsBottomRight', 
     1770        tml  => <<EXPT, 
     1771| A1 | A2 | A3 | 
     1772| B1 | X || 
     1773| C1 | ^ | 
     1774EXPT 
     1775        html => <<HEXPT, 
     1776<table border="1" cellpadding="0" cellspacing="1"> 
     1777<tr><td>A1</td><td>A2</td><td>A3</td></tr> 
     1778<tr><td>B1</td><td rowspan="2" colspan="2">X</td></tr> 
     1779<tr><td>C1</td></tr> 
     1780</table> 
     1781HEXPT 
     1782    }, 
     1783    { 
     1784        exec => $TML2HTML | $ROUNDTRIP, 
     1785        name => 'notAlwaysRowSpan', 
     1786        tml  => <<EXPT, 
     1787| ^ | B | 
     1788| ^ | <nop>^ | 
     1789EXPT 
     1790        html => <<HEXPT, 
     1791<table border="1" cellpadding="0" cellspacing="1"> 
     1792<tr><td rowspan="2">^</td><td>B</td></tr> 
     1793<tr><td>$protecton&lt;nop&gt;$protectoff^</td></tr> 
     1794</table> 
     1795HEXPT 
     1796    }, 
     1797    { 
    16251798        exec => $HTML2TML | $ROUNDTRIP, 
    16261799        name => 'collapse', 
     
    18051978        html => <<THERE, 
    18061979<table cellspacing="1" cellpadding="0" border="1"> 
    1807 <tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td>Main.SomeGuy</td></tr> 
     1980<tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td><span class="WYSIWYG_LINK">Main.SomeGuy</span></td></tr> 
    18081981</table> 
    18091982<span class="WYSIWYG_PROTECTED"><br />%TABLESEP%</span> 
     
    18201993        html => <<THERE, 
    18211994<table cellspacing="1" cellpadding="0" border="1"> 
    1822 <tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td>Main.SomeGuy</td></tr> 
     1995<tr><td><span class="WYSIWYG_LINK">[[LegacyTopic1]]</span></td><td><span class="WYSIWYG_LINK">Main.SomeGuy</span></td></tr> 
    18231996</table> 
    18241997<span class="WYSIWYG_PROTECTED"><br />%SEARCH{"legacy" nonoise="on" format="| [[\$topic]] | [[\$wikiname]] |"}%</span> 
     1998THERE 
     1999    }, 
     2000    { 
     2001        name => 'linkInTable', 
     2002        exec => $ROUNDTRIP | $TML2HTML, 
     2003        tml  => <<HERE, 
     2004| Main.SomeGuy | 
     2005| - Main.SomeGuy - | 
     2006Main.SomeGuy 
     2007HERE 
     2008        html => <<THERE, 
     2009<table cellspacing="1" cellpadding="0" border="1"> 
     2010<tr><td><span class="WYSIWYG_LINK">Main.SomeGuy</span></td></tr> 
     2011<tr><td> - <span class="WYSIWYG_LINK">Main.SomeGuy</span> - </td></tr> 
     2012</table> 
     2013<span class="WYSIWYG_LINK">Main.SomeGuy</span> 
    18252014THERE 
    18262015    }, 
     
    20422231        name => "Item2222", 
    20432232        exec => $ROUNDTRIP | $CANNOTWYSIWYG, 
    2044         tml => '<!-- <sticky></sticky> -->', 
     2233        tml  => '<!-- <sticky></sticky> -->', 
    20452234    }, 
    20462235]; 
     
    20742263            my $fn = 'TranslatorTests::testCANNOTWYSIWYG_' . $datum->{name}; 
    20752264            no strict 'refs'; 
    2076             *$fn = sub { my $this = shift; $this->compareNotWysiwygEditable($datum) }; 
     2265            *$fn = 
     2266              sub { my $this = shift; $this->compareNotWysiwygEditable($datum) }; 
    20772267            use strict 'refs'; 
    20782268        } 
     
    21222312    } 
    21232313    $query->path_info("/Current/TestTopic"); 
    2124     $this->{session}->finish() if (defined($this->{session})); 
     2314    $this->{session}->finish() if ( defined( $this->{session} ) ); 
    21252315    $this->{session} = new Foswiki( undef, $query ); 
    21262316    $Foswiki::Plugins::SESSION = $this->{session}; 
     
    21352325} 
    21362326 
    2137 sub TML_HTMLconverterOptions 
    2138 { 
     2327sub TML_HTMLconverterOptions { 
    21392328    my $this = shift; 
    21402329    return { 
     
    21602349    $tml =~ s/%!page!%/$page/g; 
    21612350 
    2162     my $notEditable = Foswiki::Plugins::WysiwygPlugin::notWysiwygEditable( $tml ); 
    2163     $this->assert(!$notEditable, $notEditable); 
     2351    my $notEditable = Foswiki::Plugins::WysiwygPlugin::notWysiwygEditable($tml); 
     2352    $this->assert( !$notEditable, $notEditable ); 
    21642353 
    21652354    my $txer = new Foswiki::Plugins::WysiwygPlugin::TML2HTML(); 
    2166     my $tx   = $txer->convert( 
    2167         $tml, 
    2168         $this->TML_HTMLconverterOptions() 
    2169     ); 
     2355    my $tx = $txer->convert( $tml, $this->TML_HTMLconverterOptions() ); 
    21702356 
    21712357    $this->assert_html_equals( $html, $tx ); 
     
    21852371    $tml =~ s/%!page!%/$page/g; 
    21862372 
    2187     my $notEditable = Foswiki::Plugins::WysiwygPlugin::notWysiwygEditable( $tml, '' ); 
    2188     $this->assert($notEditable, "This TML should not be wysiwyg-editable: $tml"); 
     2373    my $notEditable = 
     2374      Foswiki::Plugins::WysiwygPlugin::notWysiwygEditable( $tml, '' ); 
     2375    $this->assert( $notEditable, 
     2376        "This TML should not be wysiwyg-editable: $tml" ); 
    21892377} 
    21902378 
     
    22002388 
    22012389    my $txer = new Foswiki::Plugins::WysiwygPlugin::TML2HTML(); 
    2202     # This conversion can throw an exception.  
     2390 
     2391    # This conversion can throw an exception. 
    22032392    # This might be expected if $args->{exec} also has $CANNOTWYSIWYG set 
    2204     my $html = eval { 
    2205         $txer->convert( 
    2206             $tml, 
    2207             $this->TML_HTMLconverterOptions() 
    2208         ); 
    2209     }; 
     2393    my $html = 
     2394      eval { $txer->convert( $tml, $this->TML_HTMLconverterOptions() ); }; 
    22102395    $html = $@ if $@; 
    22112396 
    22122397    $txer = new Foswiki::Plugins::WysiwygPlugin::HTML2TML(); 
    2213     my $tx = $txer->convert( 
    2214         $html, 
    2215         $this->HTML_TMLconverterOptions() 
    2216     ); 
     2398    my $tx = $txer->convert( $html, $this->HTML_TMLconverterOptions() ); 
    22172399    my $finaltml = $args->{finaltml} || $tml; 
    22182400    $finaltml =~ s/%!page!%/$page/g; 
    22192401 
    2220     my $notEditable = Foswiki::Plugins::WysiwygPlugin::notWysiwygEditable( $tml, '' ); 
     2402    my $notEditable = 
     2403      Foswiki::Plugins::WysiwygPlugin::notWysiwygEditable( $tml, '' ); 
    22212404    if ( ( $mask & $args->{exec} ) & $CANNOTWYSIWYG ) { 
    2222         $this->assert($notEditable, "This TML should not be wysiwyg-editable: $tml"); 
    2223         # Expect that roundtrip is not possible if notWysiwygEditable returns true. 
    2224         # notWysiwygEditable should not return false for anything that *can* be 
    2225         # roundtripped. 
     2405        $this->assert( $notEditable, 
     2406            "This TML should not be wysiwyg-editable: $tml" ); 
     2407 
     2408     # Expect that roundtrip is not possible if notWysiwygEditable returns true. 
     2409     # notWysiwygEditable should not return false for anything that *can* be 
     2410     # roundtripped. 
    22262411        $this->_assert_tml_not_equals( $finaltml, $tx, $args->{name} ); 
    22272412    } 
    22282413    else { 
    22292414        $this->_assert_tml_equals( $finaltml, $tx, $args->{name} ); 
    2230         $this->assert(!$notEditable, "$args->{name} TML is wysiwyg-editable, but notWysiwygEditable() reports: $notEditable"); 
     2415        $this->assert( !$notEditable, 
     2416"$args->{name} TML is wysiwyg-editable, but notWysiwygEditable() reports: $notEditable" 
     2417        ); 
    22312418    } 
    22322419 
    22332420} 
    22342421 
    2235 sub HTML_TMLconverterOptions 
    2236 { 
     2422sub HTML_TMLconverterOptions { 
    22372423    my $this = shift; 
    22382424    return { 
     
    22582444 
    22592445    my $txer = new Foswiki::Plugins::WysiwygPlugin::HTML2TML(); 
    2260     my $tx   = $txer->convert( 
    2261         $html, 
    2262         $this->HTML_TMLconverterOptions() 
    2263     ); 
     2446    my $tx = $txer->convert( $html, $this->HTML_TMLconverterOptions() ); 
    22642447    $this->_assert_tml_equals( $finaltml, $tx, $args->{name} ); 
    22652448} 
     
    23102493    if ( $expected eq $actual ) { 
    23112494        my $expl = 
    2312             "==$name== Actual TML unexpectedly correct, remove \$CANNOTWYSIWYG flag:\n" 
     2495"==$name== Actual TML unexpectedly correct, remove \$CANNOTWYSIWYG flag:\n" 
    23132496          . encode($actual) 
    23142497          . "\n==$name==\n"; 
Note: See TracChangeset for help on using the changeset viewer.