@krautzource/sre-to-tree
Advanced tools
Comparing version 2.0.2 to 3.0.0
@@ -5,2 +5,18 @@ # Changelog | ||
## [3.0.0](https://github.com/krautzource/sre-to-tree/compare/v2.0.2...v3.0.0) (2022-09-22) | ||
### ⚠ BREAKING CHANGES | ||
* Removes data-href, makes anchors active. | ||
### Features | ||
* revise anchor handling ([3f60216](https://github.com/krautzource/sre-to-tree/commit/3f60216669189445a1ed4730ef4a931cd330330a)), closes [#33](https://github.com/krautzource/sre-to-tree/issues/33) | ||
### Bug Fixes | ||
* tree root should not have level ([281f86c](https://github.com/krautzource/sre-to-tree/commit/281f86ca0ec75f12349324d657cfce1474a86dca)), closes [#30](https://github.com/krautzource/sre-to-tree/issues/30) | ||
### [2.0.2](https://github.com/krautzource/sre-to-tree/compare/v2.0.1...v2.0.2) (2021-11-11) | ||
@@ -7,0 +23,0 @@ |
19
lib.js
@@ -35,8 +35,8 @@ /** | ||
node.setAttribute('data-owns-id', node.getAttribute('data-semantic-id')); | ||
level++; | ||
node.setAttribute('aria-level', level); | ||
if (Number.isInteger(index) && array.length) { | ||
node.setAttribute('aria-level', level); | ||
node.setAttribute('aria-posinset', ++index); | ||
node.setAttribute('aria-setsize', array.length); | ||
} | ||
level++; | ||
generateLabelAndRole(node); | ||
@@ -96,2 +96,3 @@ const semanticOwned = node.getAttribute('data-semantic-owns'); | ||
if (child.getAttribute('role')) return; | ||
// general rule: make it presentation (removing it from the accessibility tree) | ||
if (child.tagName.toUpperCase() !== 'A' || !child.hasAttribute('href')) { | ||
@@ -101,2 +102,4 @@ child.setAttribute('role', 'presentation'); | ||
} | ||
// rewrite (proper) links | ||
// NOTE. Since MathJax does not support <a> in internal format, the SRE structure is placed inside the a. We assume it's on the first semantic child | ||
const firstSemanticChild = child.querySelector('[data-semantic-speech]'); | ||
@@ -107,6 +110,12 @@ if (!firstSemanticChild) { | ||
} | ||
firstSemanticChild.setAttribute('data-href', child.getAttribute('href')); | ||
firstSemanticChild.setAttribute( | ||
// move all attributes | ||
[...firstSemanticChild.attributes].forEach(attr => { | ||
child.setAttribute(attr.name, attr.value); | ||
firstSemanticChild.removeAttribute(attr.name); | ||
}) | ||
firstSemanticChild.setAttribute('role', 'presentation'); | ||
// tweak aria-label | ||
child.setAttribute( | ||
'aria-label', | ||
firstSemanticChild.getAttribute('aria-label') + ' link' | ||
child.getAttribute('aria-label') + ' link' | ||
); // TODO R&D braille display affordances and how to fit them together with Nemeth | ||
@@ -113,0 +122,0 @@ }; |
{ | ||
"name": "@krautzource/sre-to-tree", | ||
"version": "2.0.2", | ||
"version": "3.0.0", | ||
"description": "Rewritig speech-rule-engine enriched DOM nodes to a labeled WAI ARIA tree", | ||
@@ -29,4 +29,4 @@ "main": "lib.js", | ||
"jsdom": "^18.0.1", | ||
"mathjax-full": "^3.2.0", | ||
"speech-rule-engine": "^4.0.0-beta.2", | ||
"mathjax-full": "github:amermathsoc/MathJax-src#991fda683aedc6bd81247f2681392f93ef9cb640", | ||
"speech-rule-engine": "4.0.6", | ||
"standard-version": "^9.3.2", | ||
@@ -33,0 +33,0 @@ "tape": "^5.3.1" |
@@ -5,11 +5,14 @@ const test = require('tape'); | ||
test('anchors', (t) => { | ||
t.plan(4); | ||
const out = tex2svg('a = \\href{//example.com}{link}'); | ||
test('anchors', async (t) => { | ||
t.plan(5); | ||
const out = await tex2svg('a = \\href{//example.com}{link}'); | ||
const svg = out.firstElementChild; | ||
sre2tree(svg); | ||
t.notOk(svg.querySelector('a').getAttribute('role') , 'anchors do not get role (presentation'); | ||
t.equal(svg.querySelector('a > [data-semantic-speech]'), svg.querySelector('a > [data-href]'), 'Link "pushed" to first semantic child'); | ||
t.equal(svg.querySelector('a').getAttribute('href'), svg.querySelector('a > [data-href]').getAttribute('data-href'), '"pushed" Link data-href value'); | ||
t.ok(svg.querySelector('a > [data-href]').getAttribute('aria-label').endsWith(' link'), '"pushed" fake-link aria-label affordance'); | ||
const theLink = svg.querySelector('a[href]'); | ||
console.log(svg.outerHTML); | ||
t.equal(theLink.getAttribute('role'), 'treeitem' , 'Anchor gets role from "real" SRE node'); | ||
t.equal(theLink.getAttribute('data-owns-id'), '9', 'Anchor gets data-owns-id from "real" SRE node'); | ||
t.notOk(theLink.querySelector('[data-owns-id="9"]'), 'Anchor descendents do not have the same data-owns-id, i.e., removed from "real" SRE node.') | ||
t.equal(theLink.getAttribute('data-owns'), '2 6 3 7 4 8 5', 'Anchor gets data-owns from "real" SRE node'); | ||
t.equal(theLink.getAttribute('aria-label'), 'l i n k link', 'Anchor gets aria-label from "real" SRE node'); | ||
}); |
@@ -5,5 +5,5 @@ const test = require('tape'); | ||
test('a first few tests', (t) => { | ||
test('a first few tests', async (t) => { | ||
t.plan(6); | ||
const out = tex2svg('f(x) = y'); | ||
const out = await tex2svg('f(x) = y'); | ||
const svg = out.firstElementChild; | ||
@@ -10,0 +10,0 @@ sre2tree(svg); // NOTE with SVG output, rewrite the SVG node cf. krautzource/sre-to-tree#6 |
@@ -5,9 +5,9 @@ const test = require('tape'); | ||
test('prevent empty aria-label', (t) => { | ||
test('prevent empty aria-label', async (t) => { | ||
t.plan(2); | ||
const out = tex2svg('a \\quad b'); | ||
const out = await tex2svg('a \\quad b'); | ||
const svg = out.firstElementChild; | ||
sre2tree(svg); | ||
t.notOk(svg.querySelector('[aria-label=""]'), 'aria-label is not empty'); | ||
const out2 = tex2svg('\\int a'); | ||
const out2 = await tex2svg('\\int a'); | ||
const svg2 = out2.firstElementChild; | ||
@@ -14,0 +14,0 @@ sre2tree(svg2); |
@@ -5,5 +5,5 @@ const test = require('tape'); | ||
test('aria-braillelabel', (t) => { | ||
test('aria-braillelabel', async (t) => { | ||
t.plan(2); | ||
const out = tex2svg('f(x) = y'); | ||
const out = await tex2svg('f(x) = y'); | ||
const svg = out.firstElementChild; | ||
@@ -10,0 +10,0 @@ sre2tree(svg); // NOTE with SVG output, rewrite the SVG node cf. krautzource/sre-to-tree#6 |
@@ -6,3 +6,3 @@ const test = require('tape'); | ||
test('failure tests', (t) => { | ||
test('failure tests', async (t) => { | ||
t.plan(3); | ||
@@ -13,7 +13,8 @@ const dom = new JSDOM( | ||
const p = dom.window.document.querySelector('p'); | ||
t.equal(sre2tree(p), p, 'Noop when no SRE markup'); | ||
const result = sre2tree(p); | ||
t.equal(result, p, 'Noop when no SRE markup'); | ||
const div = dom.window.document.querySelector('div'); | ||
const processedDiv = sre2tree(div) | ||
const processedDiv = await sre2tree(div) | ||
t.equal(processedDiv.getAttribute('data-owns'), '', 'Graceful failure with unexpected markup: cut off tree'); | ||
t.equal(processedDiv.getAttribute('aria-label'), 'bla', 'Graceful failure with unexpected markup: label intact'); | ||
}); |
@@ -5,7 +5,9 @@ | ||
const out = tex2svg('\\begin{eqnarray} x \\tag{1} \\\\a \\tag{x}\\end{eqnarray}'); | ||
const svg = out.firstElementChild; | ||
sre2tree(svg); | ||
const sreProperOwns = tex2svg('= a{bc}'); | ||
const sreProperOwnsSvg = sreProperOwns.firstElementChild; | ||
sre2tree(sreProperOwnsSvg); | ||
(async () => { | ||
const out = await tex2svg('\\begin{eqnarray} x \\tag{1} \\\\a \\tag{x}\\end{eqnarray}'); | ||
const svg = out.firstElementChild; | ||
sre2tree(svg); | ||
const sreProperOwns = await tex2svg('= a{bc}'); | ||
const sreProperOwnsSvg = sreProperOwns.firstElementChild; | ||
sre2tree(sreProperOwnsSvg); | ||
})() |
@@ -5,11 +5,12 @@ const test = require('tape'); | ||
test('aria positioning', (t) => { | ||
t.plan(3); | ||
const out = tex2svg('a+b = c'); | ||
test('aria positioning', async (t) => { | ||
t.plan(4); | ||
const out = await tex2svg('a+b = c'); | ||
const svg = out.firstElementChild; | ||
sre2tree(svg); // NOTE with SVG output, rewrite the SVG node cf. krautzource/sre-to-tree#6 | ||
t.equal(svg.getAttribute('aria-level'), '1', 'aria-level of root'); | ||
t.ok(svg.getAttribute('role') === 'tree' && !svg.getAttribute('aria-level'), 'no aria-level on tree root'); | ||
t.equal(svg.querySelectorAll('[aria-level="1"]').length, 3, 'aria-level check'); | ||
t.equal(svg.querySelectorAll('[aria-setsize="3"]').length, 6, 'elements with aria-setsize 3'); | ||
t.equal(svg.querySelectorAll('[aria-posinset="1"]+[aria-posinset="2"]+[aria-posinset="3"]').length, 2, 'elements with aria-posinset 3, preceded by posinset 2 and 1'); | ||
}); |
const sre = require('speech-rule-engine'); | ||
sre.setupEngine({ | ||
domain: 'mathspeak', | ||
style: 'default', | ||
locale: 'en', | ||
speech: 'deep', | ||
structure: true, | ||
mode: 'sync', | ||
}); | ||
sre.engineReady(); | ||
// TeX to MathML | ||
@@ -47,3 +39,7 @@ const TeX = require('mathjax-full/js/input/tex.js').TeX; | ||
const mml = new MathML(); | ||
const svg = new SVG(); | ||
const svg = new SVG({ | ||
linebreaks: { | ||
inline: true, | ||
}, | ||
}); | ||
@@ -54,5 +50,14 @@ const svghtml = mathjax.document('', { InputJax: mml, OutputJax: svg }); | ||
const mjenrich = (texstring, displayBool) => { | ||
const mjenrich = async (texstring, displayBool) => { | ||
// set up MathSpeak output | ||
await sre.setupEngine({ | ||
domain: 'mathspeak', | ||
style: 'default', | ||
locale: 'en', | ||
speech: 'deep', | ||
structure: true, | ||
}); | ||
await sre.engineReady(); | ||
const mml = tex2mml(texstring, displayBool); | ||
const enrichedMml = sre.toEnriched(mml).toString(); | ||
const enrichedMml = await sre.toEnriched(mml).toString(); | ||
const mjx = svghtml.convert(enrichedMml, { | ||
@@ -64,4 +69,4 @@ em: 16, | ||
// switch SRE to Braille | ||
sre.setupEngine({ | ||
// switch sre to Braille | ||
await sre.setupEngine({ | ||
domain: 'default', | ||
@@ -73,6 +78,5 @@ style: 'default', | ||
structure: true, | ||
mode: 'sync', | ||
}); | ||
sre.engineReady(); | ||
const enrichedMmlBraille = sre.toEnriched(mml).toString(); | ||
await sre.engineReady(); | ||
const enrichedMmlBraille = await sre.toEnriched(mml).toString(); | ||
const dom = new JSDOM(`<!DOCTYPE html>${enrichedMmlBraille}`); | ||
@@ -79,0 +83,0 @@ const brailleDoc = dom.window.document; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
96660
16
330