From edf5b7d81355bc7f8b8f3e11286d10a936de3464 Mon Sep 17 00:00:00 2001 From: Loris Bettazza Date: Fri, 8 Jan 2021 02:36:47 +0100 Subject: [PATCH 01/10] Obvious easy changes --- bootstrap-toc.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/bootstrap-toc.js b/bootstrap-toc.js index 534f100..31adc42 100644 --- a/bootstrap-toc.js +++ b/bootstrap-toc.js @@ -19,7 +19,7 @@ }, generateUniqueIdBase: function(el) { - var text = $(el).text(); + var text = el.textContent; // adapted from // https://github.com/bryanbraun/anchorjs/blob/65fede08d0e4a705f72f1e7e6284f643d5ad3cf3/anchor.js#L237-L257 @@ -78,18 +78,19 @@ }, generateNavEl: function(anchor, text) { - var $a = $(''); - $a.attr("href", "#" + anchor); - $a.text(text); + var a = document.createElement("a"); + a.classList.add("nav-link"); + a.setAttribute("href", "#" + anchor); + a.innerText = text; var $li = $("
  • "); - $li.append($a); + $li.append(a); return $li; }, generateNavItem: function(headingEl) { var anchor = this.generateAnchor(headingEl); - var $heading = $(headingEl); - var text = $heading.data("toc-text") || $heading.text(); + var text = + headingEl.getAttribute("data-toc-text") || headingEl.textContent; return this.generateNavEl(anchor, text); }, From d92f438c238d56e31c819786e2b28fd5c3f65d48 Mon Sep 17 00:00:00 2001 From: Loris Bettazza Date: Fri, 8 Jan 2021 02:48:57 +0100 Subject: [PATCH 02/10] Partial 1 --- bootstrap-toc.js | 22 ++++++++++++---------- test/toc-test.js | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/bootstrap-toc.js b/bootstrap-toc.js index 31adc42..d329c50 100644 --- a/bootstrap-toc.js +++ b/bootstrap-toc.js @@ -68,13 +68,15 @@ }, createNavList: function() { - return $(''); + var ul = document.createElement("ul"); + ul.classList.add("nav", "navbar-nav"); + return ul; }, createChildNavList: function($parent) { - var $childList = this.createNavList(); - $parent.append($childList); - return $childList; + var childList = this.createNavList(); + $parent.append(childList); + return childList; }, generateNavEl: function(anchor, text) { @@ -82,9 +84,9 @@ a.classList.add("nav-link"); a.setAttribute("href", "#" + anchor); a.innerText = text; - var $li = $("
  • "); - $li.append(a); - return $li; + var li = document.createElement("li"); + li.appendChild(a); + return li; }, generateNavItem: function(headingEl) { @@ -126,7 +128,7 @@ var helpers = this; $headings.each(function(i, el) { - var $newNav = helpers.generateNavItem(el); + var $newNav = $(helpers.generateNavItem(el)); var navLevel = helpers.getNavLevel(el); // determine the proper $context @@ -135,7 +137,7 @@ $context = $topContext; } else if ($prevNav && $context === $topContext) { // create a new level of the tree and switch to it - $context = helpers.createChildNavList($prevNav); + $context = $(helpers.createChildNavList($prevNav)); } // else use the current $context $context.append($newNav); @@ -165,7 +167,7 @@ // ensure that the data attribute is in place for styling opts.$nav.attr("data-toggle", "toc"); - var $topContext = this.helpers.createChildNavList(opts.$nav); + var $topContext = $(this.helpers.createChildNavList(opts.$nav)); var topLevel = this.helpers.getTopLevel(opts.$scope); var $headings = this.helpers.getHeadings(opts.$scope, topLevel); this.helpers.populateNav($topContext, topLevel, $headings); diff --git a/test/toc-test.js b/test/toc-test.js index 73e3c9d..9a22e27 100644 --- a/test/toc-test.js +++ b/test/toc-test.js @@ -8,21 +8,24 @@ describe("Toc", function() { describe(".helpers", function() { describe(".generateNavItem()", function() { it("uses text within the element by default", function() { - var heading = $("

    foo

    ")[0]; - var $navItem = Toc.helpers.generateNavItem(heading); - expect($navItem.text()).to.eql("foo"); + var heading = document.createElement("h1"); + heading.innerText = "foo"; + var navItem = Toc.helpers.generateNavItem(heading); + expect(navItem.textContent).to.eql("foo"); }); it("uses text specified as a data-toc-text attribute", function() { - var heading = $('

    bar

    ')[0]; - var $navItem = Toc.helpers.generateNavItem(heading); - expect($navItem.text()).to.eql("foo"); + var heading = document.createElement("h1"); + heading.innerText = "bar"; + heading.setAttribute("data-toc-text", "foo"); + var navItem = Toc.helpers.generateNavItem(heading); + expect(navItem.textContent).to.eql("foo"); }); it("keeps the text from within the element escaped", function() { var heading = document.createElement("h1"); heading.innerText = "<script>foo</script>"; - var navItem = Toc.helpers.generateNavItem(heading)[0]; + var navItem = Toc.helpers.generateNavItem(heading); expect(navItem.textContent).to.eql("<script>foo</script>"); }); @@ -33,8 +36,8 @@ describe("Toc", function() { "<script>foo</script>" ); heading.innerText = "bar"; - var $navItem = Toc.helpers.generateNavItem(heading); - expect($navItem.text()).to.eql("<script>foo</script>"); + var navItem = Toc.helpers.generateNavItem(heading); + expect(navItem.textContent).to.eql("<script>foo</script>"); }); }); From ad987471b47a8aa66a00789d292c8c18072698e7 Mon Sep 17 00:00:00 2001 From: Loris Bettazza Date: Fri, 8 Jan 2021 03:16:42 +0100 Subject: [PATCH 03/10] Partial 2 --- bootstrap-toc.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bootstrap-toc.js b/bootstrap-toc.js index d329c50..9ebc5fe 100644 --- a/bootstrap-toc.js +++ b/bootstrap-toc.js @@ -73,9 +73,9 @@ return ul; }, - createChildNavList: function($parent) { + createChildNavList: function(parent) { var childList = this.createNavList(); - $parent.append(childList); + parent.appendChild(childList); return childList; }, @@ -124,25 +124,25 @@ populateNav: function($topContext, topLevel, $headings) { var $context = $topContext; - var $prevNav; + var prevNav; var helpers = this; $headings.each(function(i, el) { - var $newNav = $(helpers.generateNavItem(el)); + var newNav = helpers.generateNavItem(el); var navLevel = helpers.getNavLevel(el); // determine the proper $context if (navLevel === topLevel) { // use top level $context = $topContext; - } else if ($prevNav && $context === $topContext) { + } else if (prevNav && $context === $topContext) { // create a new level of the tree and switch to it - $context = $(helpers.createChildNavList($prevNav)); + $context = $(helpers.createChildNavList(prevNav)); } // else use the current $context - $context.append($newNav); + $context.append(newNav); - $prevNav = $newNav; + prevNav = newNav; }); }, @@ -167,7 +167,7 @@ // ensure that the data attribute is in place for styling opts.$nav.attr("data-toggle", "toc"); - var $topContext = $(this.helpers.createChildNavList(opts.$nav)); + var $topContext = $(this.helpers.createChildNavList(opts.$nav[0])); var topLevel = this.helpers.getTopLevel(opts.$scope); var $headings = this.helpers.getHeadings(opts.$scope, topLevel); this.helpers.populateNav($topContext, topLevel, $headings); From 6eca81f85a6fae00e9fcf08b146b26f416898599 Mon Sep 17 00:00:00 2001 From: Loris Bettazza Date: Fri, 8 Jan 2021 04:46:16 +0100 Subject: [PATCH 04/10] Partial 3 --- bootstrap-toc.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bootstrap-toc.js b/bootstrap-toc.js index 9ebc5fe..2c63b1d 100644 --- a/bootstrap-toc.js +++ b/bootstrap-toc.js @@ -122,8 +122,8 @@ return parseInt(el.tagName.charAt(1), 10); }, - populateNav: function($topContext, topLevel, $headings) { - var $context = $topContext; + populateNav: function(topContext, topLevel, $headings) { + var context = topContext; var prevNav; var helpers = this; @@ -131,16 +131,16 @@ var newNav = helpers.generateNavItem(el); var navLevel = helpers.getNavLevel(el); - // determine the proper $context + // determine the proper context if (navLevel === topLevel) { // use top level - $context = $topContext; - } else if (prevNav && $context === $topContext) { + context = topContext; + } else if (prevNav && context === topContext) { // create a new level of the tree and switch to it - $context = $(helpers.createChildNavList(prevNav)); - } // else use the current $context + context = helpers.createChildNavList(prevNav); + } // else use the current context - $context.append(newNav); + context.appendChild(newNav); prevNav = newNav; }); @@ -167,10 +167,10 @@ // ensure that the data attribute is in place for styling opts.$nav.attr("data-toggle", "toc"); - var $topContext = $(this.helpers.createChildNavList(opts.$nav[0])); + var topContext = this.helpers.createChildNavList(opts.$nav[0]); var topLevel = this.helpers.getTopLevel(opts.$scope); var $headings = this.helpers.getHeadings(opts.$scope, topLevel); - this.helpers.populateNav($topContext, topLevel, $headings); + this.helpers.populateNav(topContext, topLevel, $headings); } }; From 514b16a68109b11fbd94611d9f1f8823833e0749 Mon Sep 17 00:00:00 2001 From: Loris Bettazza Date: Fri, 8 Jan 2021 07:04:33 +0100 Subject: [PATCH 05/10] Partial 4 --- bootstrap-toc.js | 52 +++++++++++++++++++++++++++++++----------------- test/toc-test.js | 26 +++++++++++------------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/bootstrap-toc.js b/bootstrap-toc.js index 2c63b1d..2e00908 100644 --- a/bootstrap-toc.js +++ b/bootstrap-toc.js @@ -8,14 +8,30 @@ window.Toc = { helpers: { // return all matching elements in the set, or their descendants - findOrFilter: function($el, selector) { - // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ - // http://stackoverflow.com/a/12731439/358804 - var $descendants = $el.find(selector); - return $el - .filter(selector) - .add($descendants) - .filter(":not([data-toc-skip])"); + findOrFilter: function(el, selector) { + var parent = el.parentElement || el; + var descendants = parent.querySelectorAll(selector); + var arr = []; + + for (var i = 0; i < descendants.length; i++) { + var descendent = descendants[i]; + if ( + descendent === el || + (descendent.parentElement !== el.parentElement && + descendent.getAttribute("data-toc-skip") === null) + ) { + arr.push(descendent); + } + } + + return arr.filter(function(item) { + if (item === el) return true; + while (item !== null) { + if (item.parentElement === el) return true; + item = item.parentElement; + } + return false; + }); }, generateUniqueIdBase: function(el) { @@ -97,10 +113,10 @@ }, // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). - getTopLevel: function($scope) { + getTopLevel: function(scope) { for (var i = 1; i <= 6; i++) { - var $headings = this.findOrFilter($scope, "h" + i); - if ($headings.length > 1) { + var headings = this.findOrFilter(scope, "h" + i); + if (headings.length > 1) { return i; } } @@ -109,25 +125,25 @@ }, // returns the elements for the top level, and the next below it - getHeadings: function($scope, topLevel) { + getHeadings: function(scope, topLevel) { var topSelector = "h" + topLevel; var secondaryLevel = topLevel + 1; var secondarySelector = "h" + secondaryLevel; - return this.findOrFilter($scope, topSelector + "," + secondarySelector); + return this.findOrFilter(scope, topSelector + "," + secondarySelector); }, getNavLevel: function(el) { return parseInt(el.tagName.charAt(1), 10); }, - populateNav: function(topContext, topLevel, $headings) { + populateNav: function(topContext, topLevel, headings) { var context = topContext; var prevNav; var helpers = this; - $headings.each(function(i, el) { + headings.forEach(function(el) { var newNav = helpers.generateNavItem(el); var navLevel = helpers.getNavLevel(el); @@ -168,9 +184,9 @@ opts.$nav.attr("data-toggle", "toc"); var topContext = this.helpers.createChildNavList(opts.$nav[0]); - var topLevel = this.helpers.getTopLevel(opts.$scope); - var $headings = this.helpers.getHeadings(opts.$scope, topLevel); - this.helpers.populateNav(topContext, topLevel, $headings); + var topLevel = this.helpers.getTopLevel(opts.$scope[0]); + var headings = this.helpers.getHeadings(opts.$scope[0], topLevel); + this.helpers.populateNav(topContext, topLevel, headings); } }; diff --git a/test/toc-test.js b/test/toc-test.js index 9a22e27..c339c32 100644 --- a/test/toc-test.js +++ b/test/toc-test.js @@ -80,24 +80,22 @@ describe("Toc", function() { describe(".getTopLevel()", function() { it("returns 1 by default", function() { - var $scope = $("
    "); - var level = Toc.helpers.getTopLevel($scope); + var scope = document.createElement("div"); + var level = Toc.helpers.getTopLevel(scope); expect(level).to.eql(1); }); it("returns the first level with more than one element", function() { - var $scope = $( - "
    " + - "

    " + - "

    " + - "

    " + - "

    " + - "
    " + - "
    " + - "
    " + - "
    " - ); - var level = Toc.helpers.getTopLevel($scope); + var scope = document.createElement("div"); + scope.innerHTML = + "

    " + + "

    " + + "

    " + + "

    " + + "
    " + + "
    " + + "
    "; + var level = Toc.helpers.getTopLevel(scope); expect(level).to.eql(6); }); }); From a20c9e6c4571d3e67b87f397d76369f447923d9c Mon Sep 17 00:00:00 2001 From: Loris Bettazza Date: Fri, 8 Jan 2021 18:08:50 +0100 Subject: [PATCH 06/10] Partial 5 --- test/toc-test.js | 66 +++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/test/toc-test.js b/test/toc-test.js index c339c32..dc235e7 100644 --- a/test/toc-test.js +++ b/test/toc-test.js @@ -1,7 +1,7 @@ -var $fixture = $("#mocha-fixture"); +var fixture = document.getElementById("mocha-fixture"); afterEach(function() { - $fixture.empty(); + fixture.innerHTML = ""; }); describe("Toc", function() { @@ -56,7 +56,8 @@ describe("Toc", function() { }); it("handles unicode", function() { - var el = $("

    💃 🕺

    ")[0]; + var el = document.createElement("h1"); + el.innerText = "💃 🕺"; var base = Toc.helpers.generateUniqueIdBase(el); expect(base).to.eql("💃-🕺"); }); @@ -70,7 +71,7 @@ describe("Toc", function() { }); it("adds a suffix when there's an existing element with that tag", function() { - $fixture.append('

    '); + fixture.innerHTML = '

    '; var el = document.createElement("h1"); var base = Toc.helpers.generateUniqueId(el); @@ -110,21 +111,21 @@ describe("Toc", function() { }); describe(".init()", function() { - var $nav; + var nav; beforeEach(function() { - $nav = $("