From 17ecce8f57f6be2c0be07aba0089702ffeb53e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Fri, 5 Aug 2016 14:48:10 +1000 Subject: [PATCH] feat: use ol in ToC (closes #835) (#909) * chore(package): update deps * feat: use ol in ToC (closes #835) * refactor(aria): query for the toc instead * style(aria): jscs fixup * refactor(aria): use less jquery * style(aria): use double quotes * fix(aria): convert NodeList to array --- js/core/structure.js | 36 ++++++------- js/w3c/aria.js | 86 +++++++++++++++++-------------- package.json | 24 ++++----- tests/spec/core/structure-spec.js | 36 +++++++------ 4 files changed, 95 insertions(+), 87 deletions(-) diff --git a/js/core/structure.js b/js/core/structure.js index ab001f2370..8c80c22f93 100644 --- a/js/core/structure.js +++ b/js/core/structure.js @@ -22,7 +22,7 @@ define( if ($secs.length === 0) { return null; } - var $ul = $(""); + var $ol = $("
    "); for (var i = 0; i < $secs.length; i++) { var $sec = $($secs[i], doc); var isIntro = $sec.hasClass("introductory"); @@ -70,9 +70,9 @@ define( var $a = $("").attr({ href: "#" + id, "class": "tocxref" }) .append(isIntro ? "" : $span.clone()) - .append($kidsHolder.contents()), - $item = $("
  1. ").append($a); - if (conf.maxTocLevel === 0 || level <= conf.maxTocLevel) $ul.append($item); + .append($kidsHolder.contents()); + var $item = $("
  2. ").append($a); + if (conf.maxTocLevel === 0 || level <= conf.maxTocLevel) $ol.append($item); current.push(0); var $sub = makeTOCAtLevel($sec, doc, current, level + 1, conf); if ($sub) { @@ -80,15 +80,15 @@ define( } current.pop(); } - return $ul; + return $ol; } return { run: function(conf, doc, cb) { - if (!conf.tocIntroductory) { + if ("tocIntroductory" in conf === false) { conf.tocIntroductory = false; } - if (!conf.maxTocLevel) { + if ("maxTocLevel" in conf === false) { conf.maxTocLevel = 0; } var $secs = $("section:not(.introductory)", doc) @@ -105,14 +105,14 @@ define( // makeTOC if (!conf.noTOC) { - var $ul = makeTOCAtLevel($("body", doc), doc, [0], 1, conf); - if (!$ul) return; - var w = "nav"; - var $sec = $("<" + w + " id='toc'/>") - .append("

    " + conf.l10n.toc + "

    ") - .append($ul), - $ref = $("#toc", doc), - replace = false; + var $ol = makeTOCAtLevel($("body", doc), doc, [0], 1, conf); + if (!$ol) return; + var nav = doc.createElement("nav"); + nav.id = "toc"; + nav.innerHTML = "

    " + conf.l10n.toc + "

    "; + nav.appendChild($ol[0]); + var $ref = $("#toc", doc); + var replace = false; if ($ref.length) { replace = true; } @@ -123,12 +123,12 @@ define( $ref = $("#abstract", doc); } if (replace) { - $ref.replaceWith($sec); + $ref.replaceWith(nav); } else { - $ref.after($sec); + $ref.after(nav); } - var $link = $("
    "); + var $link = $(""); $("body").append($link); } diff --git a/js/w3c/aria.js b/js/w3c/aria.js index 96a26658fa..6411533a47 100644 --- a/js/w3c/aria.js +++ b/js/w3c/aria.js @@ -1,45 +1,51 @@ // Module w3c/aria // Adds wai-aria landmarks and roles to entire document. // Introduced by Shane McCarron (shane@aptest.com) from the W3C PFWG - -define( - ["core/utils"], // load this to be sure that the jQuery extensions are loaded - function (utils) { - return { - run: function (conf, doc, cb) { - // ensure head section is labelled - $('body', doc).attr('role', 'document') ; - $('body', doc).attr('id', 'respecDocument') ; - $('div.head', doc).attr('role', 'contentinfo') ; - $('div.head', doc).attr('id', 'respecHeader') ; - if (!conf.noTOC) { - // ensure toc is labelled - var toc = $('nav#toc', doc).find("ul:first") ; - toc.attr('role', 'directory') ; - } - // mark issues and notes with heading - var noteCount = 0 ; var issueCount = 0 ; var ednoteCount = 0; - $(".note-title, .ednote-title, .issue-title", doc).each(function (i, item) { - var $item = $(item) - , isIssue = $item.hasClass("issue-title") - , isEdNote = $item.hasClass("ednote-title") - , level = $item.parents("section").length+2 ; - - $item.attr('aria-level', level) ; - $item.attr('role', 'heading') ; - if (isIssue) { - issueCount++; - $item.makeID('h', "issue" + issueCount) ; - } else if (isEdNote) { - ednoteCount++; - $item.makeID('h', "ednote" + ednoteCount) ; - } else { - noteCount++; - $item.makeID('h', "note" + noteCount) ; - } - }); - cb(); +"use strict"; +define([], + function() { + return { + run: function(conf, doc, cb) { + // ensure head section is labeled + if (!doc.body.hasAttribute("role")) { + doc.body.setAttribute("role", "document"); + } + if (!doc.body.hasAttribute("id")) { + doc.body.setAttribute("id", "respecDocument"); + } + var head = document.querySelector("div.head"); + if (head) { + head.setAttribute("role", "contentinfo"); + head.setAttribute("id", "respecHeader"); + } + var toc = doc.querySelector("#toc ol:first-of-type"); + if (toc) { + // ensure toc is labeled + toc.setAttribute("role", "directory"); + } + // mark issues and notes with heading + var noteCount = 1; + var issueCount = 1; + var ednoteCount = 1; + Array + .from(doc.querySelectorAll(".note-title, .ednote-title, .issue-title")) + .forEach(function(element) { + var $element = $(element); + var isIssue = element.classList.contains("issue-title"); + var isEdNote = element.classList.contains("ednote-title"); + var level = $element.parents("section").length + 2; + element.setAttribute("aria-level", level); + element.setAttribute("role", "heading"); + if (isIssue) { + $element.makeID("h", "issue" + issueCount++); + } else if (isEdNote) { + $element.makeID("h", "ednote" + ednoteCount++); + } else { + $element.makeID("h", "note" + noteCount++); } - }; - } + }); + cb(); + } + }; + } ); diff --git a/package.json b/package.json index 3beae467f2..35fbc05de2 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ }, "author": "Robin Berjon", "devDependencies": { - "async": "^2.0.0", + "async": "^2.0.1", "chai": "^3.5.0", "colors": "^1.1.2", - "command-line-args": "^3.0.0", + "command-line-args": "^3.0.1", "domReady": "github:requirejs/domReady", "epipebomb": "^0.1.1", "express": "^4.14.0", @@ -28,9 +28,9 @@ "highlight.js": "github:isagalaev/highlight.js", "jasmine-core": "^2.4.1", "jasmine-reporters": "^2.2.0", - "jquery": "^3.0.0", + "jquery": "^3.1.0", "js-beautify": "^1.6.3", - "jscs": "^3.0.6", + "jscs": "^3.0.7", "jshint": "^2.9.2", "karma": "^1.1.2", "karma-chrome-launcher": "^1.0.1", @@ -45,12 +45,12 @@ "karma-safari-launcher": "^1.0.0", "karma-safaritechpreview-launcher": "0.0.4", "karma-verbose-summary-reporter": "0.0.1", - "marcosc-async": "^3.0.0", - "mocha": "^3.0.0", + "marcosc-async": "^3.0.1", + "mocha": "^3.0.1", "moment": "^2.14.1", "mozilla-download": "^1.1.1", - "nightmare": "^2.5.2", - "promise-polyfill": "^6.0.0", + "nightmare": "^2.6.0", + "promise-polyfill": "^6.0.1", "prompt": "^1.0.0", "requirejs": "^2.2.0", "text": "github:requirejs/text", @@ -79,11 +79,11 @@ }, "dependencies": { "colors": "^1.1.2", - "command-line-args": "^3.0.0", - "command-line-usage": "^3.0.2", + "command-line-args": "^3.0.1", + "command-line-usage": "^3.0.3", "fs-promise": "^0.5.0", - "marcosc-async": "^3.0.0", - "marked": "^0.3.5", + "marcosc-async": "^3.0.1", + "marked": "^0.3.6", "nightmare": "^2.5.3", "snyk": "1.18.0" }, diff --git a/tests/spec/core/structure-spec.js b/tests/spec/core/structure-spec.js index 25f82966cb..8df6acacbd 100644 --- a/tests/spec/core/structure-spec.js +++ b/tests/spec/core/structure-spec.js @@ -20,17 +20,19 @@ describe("Core - Structure", function() { }; makeRSDoc(ops, function(doc) { // test default values - var $toc = $("#toc", doc); - expect($toc.find("h2").text()).toEqual("Table of Contents"); - expect($toc.find("h2 span").attr("resource")).toEqual("xhv:heading"); - expect($toc.find("h2 span").attr("property")).toEqual("xhv:role"); - expect($toc.find("ul:first").attr("role")).toEqual("directory"); - expect($toc.find("> ul > li").length).toEqual(3); - expect($toc.find("li").length).toEqual(15); - expect($toc.find("> ul > li a").first().text()).toEqual("1. ONE"); - expect($toc.find("a[href='#six']").text()).toEqual("1.1.1.1.1.1 SIX"); - expect($toc.find("> ul > li").first().next().find("> a").text()).toEqual("A. ONE"); - expect($toc.find("a[href='#six-1']").text()).toEqual("A.1.1.1.1.1 SIX"); + var toc = doc.getElementById("toc"); + expect(toc.querySelector("h2").textContent).toEqual("Table of Contents"); + expect(toc.querySelector("ol > li a").textContent).toEqual("1. ONE"); + expect(toc.querySelector("h2 span").getAttribute("resource")).toEqual("xhv:heading"); + expect(toc.querySelector("h2 span").getAttribute("property")).toEqual("xhv:role"); + expect(toc.querySelectorAll("li").length).toEqual(15); + expect(toc.querySelector("ol:first-of-type").childElementCount).toEqual(3); + expect(toc.querySelector("a[href='#six']").textContent).toEqual("1.1.1.1.1.1 SIX"); + expect(toc.querySelector("li:first-child").nextElementSibling.querySelector("a").textContent).toEqual("A. ONE"); + expect(toc.querySelector("a[href='#six-1']").textContent).toEqual("A.1.1.1.1.1 SIX"); + // TODO: Move test to aria-spec + // https://github.com/w3c/respec/issues/906 + expect(toc.querySelector("ol:first-of-type").getAttribute("role")).toEqual("directory"); }).then(done); }); @@ -55,10 +57,10 @@ describe("Core - Structure", function() { makeRSDoc(ops, function(doc) { var $toc = $("#toc", doc); expect($toc.find("h2").text()).toEqual("Table of Contents"); - expect($toc.find("> ul > li").length).toEqual(6); + expect($toc.find("> ol > li").length).toEqual(6); expect($toc.find("li").length).toEqual(18); - expect($toc.find("> ul > li a").first().text()).toEqual("Abstract"); - expect($toc.find("> ul > li a[href='#intro']").length).toEqual(1); + expect($toc.find("> ol > li a").first().text()).toEqual("Abstract"); + expect($toc.find("> ol > li a[href='#intro']").length).toEqual(1); }).then(done); }); @@ -71,11 +73,11 @@ describe("Core - Structure", function() { makeRSDoc(ops, function(doc) { var $toc = $("#toc", doc); expect($toc.find("h2").text()).toEqual("Table of Contents"); - expect($toc.find("> ul > li").length).toEqual(3); + expect($toc.find("> ol > li").length).toEqual(3); expect($toc.find("li").length).toEqual(11); - expect($toc.find("> ul > li a").first().text()).toEqual("1. ONE"); + expect($toc.find("> ol > li a").first().text()).toEqual("1. ONE"); expect($toc.find("a[href='#four']").text()).toEqual("1.1.1.1 FOUR"); - expect($toc.find("> ul > li").first().next().find("> a").text()).toEqual("A. ONE"); + expect($toc.find("> ol > li").first().next().find("> a").text()).toEqual("A. ONE"); expect($toc.find("a[href='#four-1']").text()).toEqual("A.1.1.1 FOUR"); }).then(done); });