build/data-tables/templates/document.hbs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{{ title }}</title>
<style id="prism-styles">{{> prismCss }}</style>
<style>
[title] {
cursor: help;
}
body {
margin: 0;
padding: 5px;
}
table {
border-collapse: collapse;
width: 100%;
}
table caption,
table th,
table td {
padding: 5px;
border: 1px solid #aaaaaa;
background: white;
}
table caption {
text-align: left;
background: #aaaaaa;
color: white;
}
tbody th {
text-align: left;
font-size: 14px;
}
tbody td {
text-align: center;
}
td > span.compare {
display: block;
}
td > span.compare.mismatch {
margin: 0 -5px -5px;
border: 5px solid red;
}
thead th[data-column="ident"] {
text-align: left;
}
table:not(#sticky-table-header) + table thead {
/*
visually hide consecutive headers
see https://w3c.github.io/wai-tutorials/forms/labels/#note-on-hiding-elements
*/
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip: rect(0 0 0 0);
}
table td[data-focusable="true"],
table td > span.compare[data-focusable="true"] {
/* focusable */
background: #FFDC00;
}
table td[data-tabbable="true"],
table td > span.compare[data-tabbable="true"] {
/* tabbable */
background: #01FF70;
}
table td[data-focusable="false"][data-tabbable="true"],
table td > span.compare[data-focusable="false"][data-tabbable="true"] {
/* only tabbable */
background: #19F1FF;
}
table td[data-focusable="false"][data-tabbable="false"],
table td > span.compare[data-focusable="false"][data-tabbable="false"] {
/* inert */
background: #DDDDDD;
}
table td[data-redirecting-to],
table td > span.compare[data-redirecting-to] {
/* redirecting */
background: #FFA9F9 !important;
}
table td[data-focusable="false"][data-tabbable="false"][data-focus-host] {
/* hosting focused element */
background: #73CCC2;
}
table td.irrelevant-to-context {
opacity: 0.5;
}
/* inline foot-note boxes */
tbody td {
position: relative;
padding: 12px 5px 5px;
margin: 1px;
}
tbody th {
position: relative;
padding: 5px 5px 12px 5px;
margin: 1px;
background: none;
}
tbody th .notes {
bottom: 1px;
right: 1px;
}
tbody td .notes {
top: 1px;
left: 1px;
}
tbody .notes {
position: absolute;
line-height: 0;
font-size: 0;
}
tbody .notes .note {
display: inline-block;
padding: 2px;
font-size: 10px;
line-height: 8px;
color: #666;
background: #EEE;
text-decoration: none;
}
tbody .notes > .note + .note {
margin-left: 1px;
}
tbody .notes > .note.tabindex-value {
background: rgba(0, 0, 0, 0.1);
}
tbody .notes > .note.warning {
color: white;
background: red;
}
tbody .notes > .note.target {
color: white;
background: black;
}
tbody .notes > .note.compare-target {
color: white;
background: black;
}
#footnotes-list li:target {
background: #EEE;
}
#floating-footnote {
position: absolute;
max-width: 500px;
padding: 10px;
border: 1px solid black;
background: white;
}
#floating-footnote h3 {
margin-top: 0;
}
#sticky-table-header {
position: fixed;
top: 0;
left: 0;
margin: 0 5px;
z-index: 1000;
}
#sticky-table-header caption {
position: relative;
}
#sticky-table-header caption ul {
position: absolute;
display: none;
top: 14px;
left: 0px;
font-size: 14px;
background: white;
border: 2px solid #AAA;
}
#sticky-table-header caption ul li {
display: block;
margin: 0;
}
#sticky-table-header caption:hover ul {
display: block;
}
code[class*="language-"] {
white-space: pre-line;
}
code .token.tag {
white-space: pre;
}
</style>
</head>
<body>
<h1>{{ title }}</h1>
{{{ introduction }}}
{{#if groups}}
<nav id="table-of-contents">
<h1>Table Of Contents</h1>
<ul>
{{#each groups}}
<li><a href="#{{ id }}">{{ label }}</a></li>
{{/each}}
<li><a href="#footnotes">Footnotes</a></li>
</ul>
</nav>
{{/if}}
{{{ table }}}
<h2 id="footnotes">Footnotes</h2>
<ul id="footnotes-list">
<li id="footnote-M">The DOM Element Interface is missing the focus method.</li>
<li id="footnote-E">The <code>focus</code> event is not emitted upon the element becoming the active element (<code>document.activeElement</code>).</li>
<li id="footnote-S">The <code>:focus</code> CSS pseudo class is not set on the element when it is the active element (<code>document.activeElement</code>).</li>
<li id="footnote-C">The element becomes the active element (<code>document.activeElement</code>) when an element of <code>contentDocument</code> or the <code>shadowRoot</code> has focus.</li>
{{#each notes}}
<li id="footnote-{{ @key }}">
<h3>Note {{ @key }}</h3>
{{{ this }}}
</li>
{{/each}}
</ul>
<script>
var headerTable;
var headerTableCaption;
var headerHeight = 0;
// make sure all tables have the same width
function justifyTableWidth() {
var tables = [].slice.call(document.querySelectorAll('table'), 0);
var largestIdentWidth = 0;
var largestDataCellWidth = 0;
// make the table consume the space it requires
tables.map(function(table) {
table.style.position = 'absolute';
table.style.width = 'auto';
});
// find the widest <th> and <td> to align everything to
tables.map(function(table) {
largestIdentWidth = Math.max(largestIdentWidth, table.querySelector('tbody th').offsetWidth);
largestDataCellWidth = Math.max.apply(Math, [].map.call(table.querySelectorAll('tbody tr:first-child td'), function(cell) {
return cell.offsetWidth;
}).concat([largestDataCellWidth]));
});
var dataCells = (tables[0].querySelectorAll('col').length - 1) * largestDataCellWidth;
// align width of <table>, <th> and <td>
tables.map(function(table) {
table.style.position = '';
table.style.width = (dataCells + largestIdentWidth) + 'px';
[].forEach.call(table.querySelectorAll('col'), function(col) {
if (col.getAttribute('data-column') === 'ident') {
return;
}
col.style.width = largestDataCellWidth + 'px';
});
});
}
// create sticky header table from first actual table
function createHeaderTable() {
var firstTable = document.querySelector('table');
headerTable = firstTable.cloneNode(true);
[].forEach.call(headerTable.querySelectorAll('tbody, tfoot'), function(element) {
element.parentNode.removeChild(element);
});
[].forEach.call(headerTable.querySelectorAll('th, td'), function(element) {
element.setAttribute('id', '');
});
var caption = headerTable.querySelector('caption');
headerTableCaption = document.createElement('span');
caption.innerHTML = '';
caption.appendChild(headerTableCaption);
headerTable.id = 'sticky-table-header';
headerTable.setAttribute('aria-hidden', 'true');
headerTable.style.width = firstTable.offsetWidth + 'px';
window.addEventListener('resize', function() {
headerTable.style.width = firstTable.offsetWidth + 'px';
}, true);
firstTable.parentNode.insertBefore(headerTable, firstTable);
headerHeight = headerTable.offsetHeight;
}
function addTableOfContentsToStickyHeader() {
var toc = document.querySelector('#table-of-contents ul');
var list = toc.cloneNode(true);
headerTableCaption.parentNode.appendChild(list);
}
// listen to scroll position to show/hide sticky header and update its caption
function bindHeaderTableScrolling() {
var headerCaption = headerTableCaption.textContent;
headerTable.style.display = 'none';
var timer;
var handleHeaderTable = function() {
if (headerTable.style.display !== 'none') {
headerTable.style.display = 'none';
}
var elementAtPoint = document.elementFromPoint(50, 0);
if (!elementAtPoint || !elementAtPoint.closest('table')) {
return;
}
// make sticky header follow horizontal scroll
var horizontalScrollOffset = (document.scrollingElement || document.body).scrollLeft
|| document.documentElement.scrollLeft
|| window.scrollX;
headerTable.style.left = (0 - horizontalScrollOffset) + 'px';
// identify the visible part of the table to update the sticky caption
var tableAtPoint = document.elementFromPoint(50, headerHeight + 20);
var table = tableAtPoint && tableAtPoint.closest('table');
var caption = table && table.querySelector('caption');
if (caption) {
if (caption.textContent !== headerCaption) {
headerCaption = caption.textContent;
headerTableCaption.textContent = headerCaption;
}
headerTable.style.display = '';
}
};
var handleScrollEvent = function() {
timer && clearTimeout(timer);
timer = setTimeout(handleHeaderTable, 50);
};
window.addEventListener('scroll', handleScrollEvent, true);
handleScrollEvent();
}
// add hight of header to fragment URI targets
function handleHashchangeEvent() {
var id = location.hash.slice(1);
var target = id && document.getElementById(id);
if (!target) {
return;
}
target.scrollIntoView({
block: 'start',
behavior: 'instant',
});
window.scrollBy(0, 0 - headerHeight);
}
function compensateHeaderTable() {
if (!window.scrollBy) {
return;
}
// https://developer.mozilla.org/en-US/docs/Web/Events/hashchange
window.addEventListener('hashchange', handleHashchangeEvent, true);
}
function bindFootnoteTooltip() {
var container = document.createElement('div');
container.id = 'floating-footnote';
container.hidden = true;
container.setAttribute('tabindex', '-1');
document.body.appendChild(container);
// position the tooltip below the anchor
document.body.addEventListener('focus', function(event) {
if (!event.target.classList.contains('note')) {
return;
}
var anchor = event.target;
var id = anchor.getAttribute('href').slice(1);
var target = document.getElementById(id);
var position = anchor.getBoundingClientRect();
var scrollTop = (document.scrollingElement || document.body).scrollTop
|| document.documentElement.scrollTop
|| window.scrollY;
container.style.top = (scrollTop + position.top + position.height) + 'px';
if (position.left + 500 > window.innerWidth) {
container.style.left = '';
container.style.right = '5px';
} else {
container.style.left = position.left + 'px';
container.style.right = '';
}
container.hidden = false;
container.innerHTML = target.innerHTML;
}, true);
// allow selecting text / clicking things in the tooltip,
// but hide it when anything else is focused
var clickedOnContainer = false;
container.addEventListener('mousedown', function() {
clickedOnContainer = true;
setTimeout(function() {
clickedOnContainer = false;
}, 100);
}, true);
document.body.addEventListener('blur', function(event) {
if (clickedOnContainer) {
return;
}
container.hidden = true;
}, true);
container.addEventListener('blur', function(event) {
container.hidden = true;
}, true);
// hide the container on ESC
document.body.addEventListener('keydown', function(event) {
if (event.keyCode !== 27 || container.hidden) {
return;
}
container.blur();
container.hidden = true;
}, true);
// abort jumping to the footnote, as we moved the relevant footnote into view on focus
document.body.addEventListener('click', function(event) {
if (!event.target.classList.contains('note') || container.hidden) {
return;
}
event.preventDefault();
}, true);
}
(function() {
// https://developer.mozilla.org/en-US/docs/Web/API/Document/elementFromPoint
// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
if (!document.elementFromPoint || !document.body.closest) {
return;
}
justifyTableWidth();
createHeaderTable();
addTableOfContentsToStickyHeader();
bindHeaderTableScrolling();
compensateHeaderTable();
document.body.addEventListener('load', function() {
handleHashchangeEvent();
});
if (document.body.hidden !== undefined) {
bindFootnoteTooltip();
}
})();
</script>
{{> tracking }}
</body>
</html>