Want to set toc start="2" by default

Hi.

As the document title is always heading 1 and there should be one heading 1 only due to accessibility reasons I configured CKEditor 4 this way:

config.format_h1 = { element: 'h2'};
config.format_h2 = { element: 'h3'};
config.format_h3 = { element: 'h4'};
config.format_h4 = { element: 'h5'};
config.format_h5 = { element: 'h6'};
// be aware: h6 is missing in tags
config.format_tags = 'p;h1;h2;h3;h4;h5;pre';

This CKEditor 5 doing by default: Headings | CKEditor 5 Documentation

But now I do have a little problem. All table of contents will have one bullet to much as macro toc starts with heading 1. I can change this with:

{{toc start="2"/}}

But the regular user will not know this. So I want to set it by default if someone uses the toc macro.

But I can’t find the toc macro to edit it. Does someone know where this macro is?

Regards, Simpel

2 Likes

Just a ping after a week. Anyone an idea or workaround?

Another idea is to have a custom skin and override rendercontent.vm, especially the part:

    #if ($displayTitle)
      <div class="document-info">
        <div id="document-title"><h1>$titleToDisplay</h1></div>
      </div>
    #end

You could replace <h1> by some <div id="..."> and then modify the CSS to style properly.

Note that we have an issue for this:
Loading... (check the comments)

It think that the document title is a perfect h1. The table of content shall default start to display from heading 2. That I want to change.

At least I want to have removed the first leading dot of the two dots in front of the first listed heading in the article.

I’m not sure since in the XWiki syntax you can have from 1 to 6 heading levels, see https://www.xwiki.org/xwiki/bin/view/Documentation/UserGuide/Features/XWikiSyntax/?syntax=2.1&section=Headings

Thus, we probably need H1-H6 for the content.

That is not a solution for everyone but for us. Most users will use wysiwyg editor. If they choose “heading 1” we let ckeditor translate it to h2. We removed “heading 6” as there is not translation to h7 possible.

Of course users can use the wiki2.0 syntax. But these users are advanced. If they use = heading = they will see something is awkward in the toc and have a look at other articles to compare and to fix it.

We want our wiki as accessible as possible. Therefore we disabled color, background color and font size in the wysiwyg editor. Of course advanced user can do this with wiki syntax. But if they do they should know why.

We are aware that our way written in post #1 has its problems but we want to deal with it. Now we search for a solution to have a good looking toc, not starting with h1 by default. Or we can think of a special styling omitting the first li-dot (representing h1). But this seems to be more problematic to me.

We found a solution which works for us. Maybe someone will get some inspiration.

The XWiki macro TOC is not directly accessible for us to make pretty. By default, the TOC always starts with header 1. However, we only allow headers from H2 in articles in the WYSIWYG editor, since the title of the article is always already H1, which may only exist once. The parameter start=“2” can be passed for the TOC, but it cannot be set as default. Thus the list would always have a nonsensical leading dot for the empty H1 of the article. But this point should disappear.

First of all, the TOC is given an ID so that you can continue working with it. Then an inserted H2 “Table of contents” is added. A frame is drawn around the whole thing for a better delimitation. Also, all list items, which are internal links, are stripped of the link underlines. It is clear that these are links. The mass of links would become very confusing with the many underlines.

Here is the code of the JavaScriptExtension:

// Add id to table of content
function addTocID() {
	let lists = document.querySelectorAll("div#xwikicontent ul");
	for (let i = 0; i<lists.length; i++) {
		if (typeof lists[i].children[0] !== "undefined") {
			if (typeof lists[i].children[0].children[0] !== "undefined") {
				if (typeof lists[i].children[0].children[0].children[0] !== "undefined") {
					if (typeof lists[i].children[0].children[0].children[0].getAttribute("href") !== "undefined" && lists[i].children[0].children[0].children[0].getAttribute("href") !== null) {
						if (lists[i].children[0].children[0].children[0].getAttribute("href").startsWith("#H")) {
                            if (lists[i].getAttribute("id") !== "ndr-toc") {
                              lists[i].setAttribute("id", "ndr-toc");
                            }
                          break;
						}
					}
				}
			}
		}
	};
    let listsEditor = document.querySelectorAll("div#xwikicontent div ul li ul");
  for (let i = 0; i<listsEditor.length; i++) {
		if (typeof listsEditor[i].children[0] !== "undefined") {
			if (typeof listsEditor[i].children[0].children[0] !== "undefined") {
				if (typeof listsEditor[i].children[0].children[0] !== "undefined") {
					if (typeof listsEditor[i].children[0].children[0].getAttribute("href") !== "undefined" && listsEditor[i].children[0].children[0].getAttribute("href") !== null) {
						if (listsEditor[i].children[0].children[0].getAttribute("href").startsWith("#H")) {
                            if (listsEditor[i].getAttribute("id") !== "ndr-toc") {
                              listsEditor[i].setAttribute("id", "ndr-toc");
                            }
							break;
						}
					}
				}
			}
		}
	};
}

// add header "Table of contents" to toc
function setHeaderToTOC() {
  // Check if div-ndr-toc exists and just got called a second time
  // NOTE: this whole script only works for the first toc.
  if (document.getElementById("div-ndr-toc") !== null) {
  	return;
  }
  let toc = document.getElementById("ndr-toc");
  if (toc !== null) {
    // create wrapper container
    let wrapper = document.createElement('div');
    wrapper.id = "div-ndr-toc";
    // insert wrapper before toc in the DOM tree
    toc.parentNode.insertBefore(wrapper, toc);
    // move toc into wrapper
    wrapper.appendChild(toc);
    // insert h2 into wrapper
    let tocDiv = document.getElementById("div-ndr-toc");
    let header = document.createElement("h2");
    let headerText = document.createTextNode("Table of contents");
    header.appendChild(headerText);
    tocDiv.insertAdjacentElement("afterbegin", header);
  }
}

// remove toc's parent li and ul element
// NOTE: the toc macro creates a table of contents starting with H1.
// We have set CKEditor to create H2 as highest headline, so there is
// no H1 in the article, leading to empty ul and li around the actual toc
// resulting in useless bullets. addTocID sets the id "ndr-toc" to
// the actual toc, so we need to remove the tocs parents (ul and li)
function removeTOCsParentLi() {
  let toc = document.getElementById("ndr-toc");
  if (toc !== null) {
    let parent = toc.parentElement;
    let fragment = document.createDocumentFragment();
    if (parent.tagName === "LI") {
      fragment.appendChild(toc);
      if (parent.parentNode.tagName === "UL") {
        parent.parentNode.parentNode.replaceChild(fragment, parent.parentNode);
      }
    }
  }
}

// NOTE: For some reason the dom updates and this listener does not get called
// I could not figure out what's wrong, so since all functions check if they
// have to add/remove something, I can safely call them twice and add a timeout
// to await the dom updates
document.observe('xwiki:dom:updated', function(event) {
  addTocID();
  removeTOCsParentLi()
  setHeaderToTOC();
  setTimeout(function() {
    addTocID();
    removeTOCsParentLi()
    setHeaderToTOC();
  }, 500);
});

addTocID();
removeTOCsParentLi()
setHeaderToTOC();

StyleSheetExtension looks like:

/* do not underline all links in toc */
#ndr-toc a {
    text-decoration: none !important;
}

/* border around TOC */
#div-ndr-toc {
    border: 1px solid #e8e8e8;
    border-radius: 4px;
    padding: 16px;
    padding-bottom: 0;
    width: fit-content;
    margin-bottom: 20px;
}

/* move heading for table of contents to same height as LI */
#div-ndr-toc h2 {
    margin-top: 0;
}

So, XWIKI-21370: Header structure uses too many H1 should be included in 15.10.2 and 16.0.0.

I opened a ticket very similar to the situation you mentionned here :slight_smile: → XRENDERING-732: Optionally use H2 as the base level for hierarchy for the ToC.

Have a good day!
Lucas C.

1 Like