spatial-navigation-polyfill
Version:
A polyfill for the spatial navigation
137 lines (124 loc) • 6.53 kB
HTML
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="application-name" content="API :spatialNavigationSearch()">
<meta name="author" content="Jeonghee Ahn">
<meta name="description" content="element.spatialNavigationSearch(dir, SpatialNavigationSearchOptions) returns the best candidate which will gain the focus.
If there isn't any candidate, it returns `null`.<br>
You can check the result of element.spatialNavigationSearch() as element with yellow borders and yellow background.</b>">
<link rel="stylesheet" href="spatnav-style.css">
<script src="spatnav-utils.js"></script>
<script src="../../polyfill/spatial-navigation-polyfill.js"></script>
<link class="codestyle" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script type="text/javascript">
let previousTarget = {};
const DIRECTION = ['left', 'right', 'up', 'down'];
const DIRECTION_CHARACTERS = {left:'◀', right:'▶', up:'▲', down:'▼',};
let redBoxes;
let redSpatNavContainer;
let purpleBoxes;
let purpleSpatNavContainer;
let SpatialNavigationSearchOptions = null;
const init = function(e) {
const focusables = document.body.focusableAreas({mode: 'all'});
for(focusable of focusables) {
focusable.addEventListener('focus', callSpatialNavigationSearch);
}
redBoxes = [...document.getElementsByClassName('b2')];
redSpatNavContainer = document.getElementsByClassName('container c1')[0];
purpleBoxes = [...document.getElementsByClassName('b3')];
purpleSpatNavContainer = document.getElementsByClassName('container c2')[0];
onChangeSelect();
};
function callSpatialNavigationSearch(e) {
const selectedOption = document.getElementById('option').value;
const currentElement = e.target;
if(previousTarget) {
for(let dir of DIRECTION) {
if(previousTarget[dir]) {
let textElem = previousTarget[dir].querySelector('.direction-text');
for (var child of previousTarget[dir].childNodes) {
if (child === textElem) previousTarget[dir].removeChild(textElem);
}
previousTarget[dir].classList.remove('will-be-focused');
}
}
}
if (selectedOption === 'dir') {
SpatialNavigationSearchOptions = null;
} else if (selectedOption === 'candidates') {
SpatialNavigationSearchOptions = {candidates: purpleBoxes};
} else if (selectedOption === 'container') {
SpatialNavigationSearchOptions = {container: redSpatNavContainer};
} else if (selectedOption === 'combination') {
SpatialNavigationSearchOptions = {candidates: purpleBoxes, container: redSpatNavContainer};
}
DIRECTION.map((dir) => {
let nextTarget = currentElement.spatialNavigationSearch(dir, SpatialNavigationSearchOptions);
if(nextTarget) {
let description = document.createElement('div');
description.className = 'direction-text';
description.innerHTML = `spatialNavigationSearch(${dir})`;
nextTarget.appendChild(description);
nextTarget.classList.add('will-be-focused');
previousTarget[dir] = nextTarget;
}
});
}
function onChangeSelect() {
const selectedOption = document.getElementById('option').value;
let optionText = null;
if (selectedOption === 'dir') {
optionText = null;
} else if (selectedOption === 'candidates') {
optionText = '{candidates: purpleBoxes}';
} else if (selectedOption === 'container') {
optionText = '{container: redSpatNavContainer}';
} else if (selectedOption === 'combination') {
optionText = '{candidates: purpleBoxes, container: redSpatNavContainer}';
}
let codeElement = document.getElementById('code');
codeElement.innerText =` // Node spatialNavigationSearch(dir, SpatialNavigationSearchOptions arg);
['left', 'right', 'up', 'down'].map((dir) => {
let nextTargetElements =
currentElement.spatialNavigationSearch(dir, ${optionText});
});`;
hljs.highlightBlock(codeElement);
}
</script>
</head>
<body onload="init()">
<div style="width:600px; height:350px; padding:20px;">
<button class="box" style="top:120px; left:20px;"></button>
<div class="container c1" id="redSpatNavContainer" style="position: relative; left:110px; width:500px; height:200px; --spatial-navigation-contain: contain;">
<p class="containerDesc">redSpatNavContainer (non-focusable)</p>
<button class="box b2" style="top:78px; left:25px;"></button>
<div class="container c2" id="purpleSpatNavContainer" tabindex=1 style="position: relative; left:60px; width:300px; height:100px; --spatial-navigation-contain: contain;">
<p class="containerDesc">purpleSpatNavContainer (focusable)</p>
<button class="box b3" style="top:40px; left:60px;"></button>
<button class="box b3" style="top:35px; left:250px;"></button>
</div>
<button class="box b2" style="top:-80px; left:300px;"></button>
<button class="box b2" style="top:-90px; left:420px;"></button>
</div>
<button class="box" style="top:-110px; left:350px;"></button>
<button class="box" style="top:-150px; left:650px;"></button>
</div>
<div class="code-select">
Parameter :
<select id="option" tabindex="-1" onchange="onChangeSelect()" style="margin:0 20px">
<option value="dir" selected>dir</option>
<option value="candidates">dir, {candidates}</option>
<option value="container">dir, {container}</option>
<option value="combination">dir, {candidates, container}</option>
</select>
</div>
<pre class="code-area">
<code id="code"></code>
</pre>
</body>
</html>