Item13886: Default id="foswikiTOC" creates illegal duplicate CSS IDs when multiple TOC macros are present.
Priority: Low
Current State: Closed
Released In: 2.1.0
Target Release: minor
Applies To: Engine
Component: TOC
Branches: Release02x00 master
Currently the TOC macro generates the following HTML fragment:
<div class="foswikiTOC" id="foswikiTOC">
When the page contains multiple TOC's the result is
multiple css ids on one page. This is not allowed. The formatting should be done based on class="foswikiTOC".
Bottom line: It is especially strange when it happens on the
PatternSkin topic, (it includes other TOCs into TWISTY) and where we saying:
Pattern skin provides a CSS based default look and feel - flexible and W3C compliant.
The
PatternSkin on the
https://validator.w3.org/nu/?doc=http%3A%2F%2Ffoswiki.org%2FSystem%2FPatternSkin produces 11 Erros and 49 Warnings, so isn't exactly
W3C compliant.
--
JozefMojzis - 04 Dec 2015
The id= field is controlled by an optional parameter %TOC{... id='mytoc'}%, and it defaults to 'foswikiTOC'. Since TOC is a special macro that's expanded only after all other macros are expanded, implementing an instance counter to generate unique ID's when none is provided is pretty simple. Since the ID is used in the "Back to TOC" anchor, we can't just remove it. ... From
VarTOC
If you don't specify an id, the anchor foswikiTOC can be used in a link: [[#foswikiTOC][Back to TOC]]
So to remain compatible.
- the first instance of %TOC% should have
id="foswikiTOC"
- Subsequent TOCs can have incremented anchors:
id="foswikiTOC2"
id="foswikiTOC3"
Fairly simple patch here. (And found an un-escaped brace that perl seems to not be complaining about.)
diff --git a/core/lib/Foswiki.pm b/core/lib/Foswiki.pm
index 093e33f..7aeb23e 100644
--- a/core/lib/Foswiki.pm
+++ b/core/lib/Foswiki.pm
@@ -3705,9 +3705,10 @@ sub expandMacros {
# 'Special plugin tag' TOC hack, must be done after all other expansions
# are complete, and has to reprocess the entire topic.
- if ( $text =~ m/%TOC(?:{.*})?%/ ) {
+ if ( $text =~ m/%TOC(?:\{.*\})?%/ ) {
require Foswiki::Macros::TOC;
- $text =~ s/%TOC(?:{(.*?)})?%/$this->TOC($text, $topicObject, $1)/ge;
+ my $toc=1;
+ $text =~ s/%TOC(?:\{(.*?)\})?%/$this->TOC($text, $topicObject, $1, $toc++)/ge;
}
# Codev.FormattedSearchWithConditionalOutput: remove <nop> lines,
diff --git a/core/lib/Foswiki/Macros/TOC.pm b/core/lib/Foswiki/Macros/TOC.pm
index 1ceb974..6593baa 100644
--- a/core/lib/Foswiki/Macros/TOC.pm
+++ b/core/lib/Foswiki/Macros/TOC.pm
@@ -37,7 +37,7 @@ BEGIN {
# * $headingPatternDa : ---++... dashes section heading
# * $headingPatternHt : <h[1-6]> HTML section heading </h[1-6]>
sub TOC {
- my ( $session, $text, $topicObject, $args ) = @_;
+ my ( $session, $text, $topicObject, $args, $tocInstance ) = @_;
require Foswiki::Attrs;
my $params = new Foswiki::Attrs($args);
@@ -45,9 +45,14 @@ sub TOC {
my $tocTopic = $params->{_DEFAULT};
my $tocWeb = $params->{web};
- my $tocId = $params->{id} || 'foswikiTOC';
+ my $tocId = $params->{id};
my $align = $params->{align};
+ unless ( defined $tocId ) {
+ $tocInstance = '' if ( ! defined $tocInstance || $tocInstance eq '1' );
+ $tocId = 'foswikiTOC'.$tocInstance;
+ }
+
if ( $tocTopic || $tocWeb ) {
$tocWeb ||= $topicObject->web;
$tocTopic ||= $topicObject->topic;
--
GeorgeClark - 04 Dec 2015
Ah.. I didnt noticed the back-to-toc. Excellent solution.
--
JozefMojzis - 04 Dec 2015