Skip to content

Commit 275abd7

Browse files
author
Jihye Hong
authored
Merge pull request w3c#2 from jeonghee27/polyfil-minorfix
Clean up some code
2 parents 82f8940 + cca017f commit 275abd7

File tree

1 file changed

+71
-159
lines changed

1 file changed

+71
-159
lines changed

polyfill/spatnav-heuristic.js

+71-159
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@
1010

1111
function focusNavigationHeuristics(spatnavPolyfillOptions) {
1212
// condition: focus delegation model = false
13+
spatnavPolyfillOptions = spatnavPolyfillOptions || {'standardName': true};
1314

1415
const ARROW_KEY_CODE = {37: 'left', 38: 'up', 39: 'right', 40: 'down'};
15-
const spinnableInputTypes = ['email', 'date', 'month', 'number', 'time', 'week'];
16-
const textInputTypes = ['password', 'text', 'search', 'tel', 'url'];
17-
18-
if (!spatnavPolyfillOptions)
19-
spatnavPolyfillOptions = {"standardName": "true" };
2016

2117
// Load SpatNav API lib
2218
const SpatNavAPI = SpatnavAPI();
@@ -31,16 +27,13 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
3127
document.addEventListener('keydown', function(e) {
3228
let focusNavigableArrowKey = {'left': true, 'up': true, 'right': true, 'down': true};
3329
const eventTarget = document.activeElement;
30+
const dir = ARROW_KEY_CODE[e.keyCode];
3431

35-
let dir = ARROW_KEY_CODE[e.keyCode];
3632
// Edge case (text input, area) : Don't move focus, just navigate cursor in text area
3733
if ((eventTarget.nodeName === 'INPUT') || eventTarget.nodeName === 'TEXTAREA')
3834
focusNavigableArrowKey = handlingEditableElement(e);
3935

40-
if (!focusNavigableArrowKey[dir]) {
41-
dir = null;
42-
}
43-
if (dir) {
36+
if (focusNavigableArrowKey[dir]) {
4437
e.preventDefault();
4538
navigate(dir);
4639
}
@@ -173,8 +166,7 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
173166
* @returns NaN
174167
*/
175168
function focusingController(bestCandidate, dir) {
176-
const eventTarget = document.activeElement;
177-
const container = eventTarget.getSpatnavContainer();
169+
const container = document.activeElement.getSpatnavContainer();
178170

179171
// When bestCandidate is found
180172
if (bestCandidate) {
@@ -282,7 +274,6 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
282274
*/
283275
function filteredCandidates(currentElm, candidates, dir, container) {
284276
const originalContainer = currentElm.getSpatnavContainer();
285-
let filteredcandidates = [];
286277
let eventTargetRect;
287278

288279
// to do
@@ -293,22 +284,17 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
293284

294285
// If D(dir) is null, let candidates be the same as visibles
295286
if (dir === undefined)
296-
filteredcandidates = candidates;
287+
return candidates;
297288

298289
/*
299290
* Else, let candidates be the subset of the elements in visibles
300291
* whose principal box’s geometric center is within the closed half plane
301292
* whose boundary goes through the geometric center of starting point and is perpendicular to D.
302293
*/
303-
else
304-
for (let i = 0; i < candidates.length; i++) {
305-
const candidateContainer = candidates[i].getSpatnavContainer();
306-
const candidateRect = candidates[i].getBoundingClientRect();
307-
if (container.contains(candidateContainer) && isOutside(candidateRect, eventTargetRect, dir))
308-
filteredcandidates.push(candidates[i]);
309-
}
310-
311-
return filteredcandidates;
294+
return candidates.filter(candidate =>
295+
container.contains(candidate.getSpatnavContainer()) &&
296+
isOutside(candidate.getBoundingClientRect(), eventTargetRect, dir)
297+
);
312298
}
313299

314300
/*
@@ -442,16 +428,7 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
442428
* @returns {sequence<Node>} - visible focusable areas
443429
*/
444430
function findVisibles(focusables) {
445-
const visibles = [];
446-
let thisElement = undefined;
447-
448-
for (let i = 0; i < focusables.length; i++) {
449-
thisElement = focusables[i];
450-
if (isVisible(thisElement)) {
451-
visibles.push(thisElement);
452-
}
453-
}
454-
return visibles;
431+
return focusables.filter(isVisible);
455432
}
456433

457434
/**
@@ -463,7 +440,7 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
463440
function findStartingPoint() {
464441
let startingPoint = document.activeElement;
465442
if (!startingPoint ||
466-
(startingPoint == document.body && !document.querySelector(':focus')) /* body isn't actually focused*/
443+
(startingPoint === document.body && !document.querySelector(':focus')) /* body isn't actually focused*/
467444
) {
468445
startingPoint = document;
469446
}
@@ -518,85 +495,54 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
518495
}
519496

520497
/* Whether this element is scrollable or not */
521-
function isScrollable() { // element, dir
522-
// parameter: element
523-
if ((arguments.length == 1 && typeof arguments[0] === 'object') ||
524-
(arguments.length == 2 && typeof arguments[0] === 'object' && arguments[1] == null)) {
525-
const element = arguments[0];
526-
527-
if (element.nodeName === 'HTML' || element.nodeName === 'BODY') return true;
528-
else if (isScrollContainer(element) && isOverflow(element)) return true;
529-
else return false;
498+
function isScrollable(element, dir) { // element, dir
499+
if (element && typeof element === 'object') {
500+
if (dir && typeof dir === 'string') { // parameter: dir, element
501+
if (isOverflow(element, dir)) {
502+
// style property
503+
const overflowX = window.getComputedStyle(element, null).getPropertyValue('overflow-x');
504+
const overflowY = window.getComputedStyle(element, null).getPropertyValue('overflow-y');
505+
506+
switch (dir) {
507+
case 'left':
508+
/* falls through */
509+
case 'right':
510+
return (overflowX !== 'visible' && overflowX !== 'clip');
511+
case 'up':
512+
/* falls through */
513+
case 'down':
514+
return (overflowY !== 'visible' && overflowY !== 'clip');
515+
}
516+
}
517+
return false;
518+
} else { // parameter: element
519+
return (element.nodeName === 'HTML' || element.nodeName === 'BODY') ||
520+
(isScrollContainer(element) && isOverflow(element));
521+
}
530522
}
523+
console.log('Need parameters for isScrollable()');
524+
return false;
525+
}
531526

532-
// parameter: dir, element
533-
else if (arguments.length == 2 && typeof arguments[0] === 'object'
534-
&& typeof arguments[1] === 'string') {
535-
const element = arguments[0];
536-
const dir = arguments[1];
537-
538-
if (isOverflow(element, dir)) {
539-
// style property
540-
const overflowX = window.getComputedStyle(element, null).getPropertyValue('overflow-x');
541-
const overflowY = window.getComputedStyle(element, null).getPropertyValue('overflow-y');
542-
527+
/* Whether this element is overflow or not */
528+
function isOverflow(element, dir) {
529+
if (element && typeof element === 'object') {
530+
if (dir && typeof dir === 'string') { // parameter: element, dir
543531
switch (dir) {
544532
case 'left':
545533
/* falls through */
546534
case 'right':
547-
return (overflowX !== 'visible' && overflowX !== 'clip');
535+
return (element.scrollWidth > element.clientWidth);
548536
case 'up':
549537
/* falls through */
550538
case 'down':
551-
return (overflowY !== 'visible' && overflowY !== 'clip');
539+
return (element.scrollHeight > element.clientHeight);
552540
}
541+
} else { // parameter: element
542+
return (element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight);
553543
}
554-
return false;
555-
}
556-
557-
else {
558-
console.log('Need parameters for isScrollable()');
559-
return false;
560-
}
561-
}
562-
563-
/* Whether this element is overflow or not */
564-
function isOverflow() {
565-
// parameter: element
566-
if (arguments.length == 1 && typeof arguments[0] === 'object') {
567-
const element = arguments[0];
568-
if (element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight) {
569-
return true;
570-
}
571-
else {
572-
return false;
573-
}
574-
}
575-
// parameter: element, dir
576-
else if (arguments.length == 2 && typeof arguments[0] === 'object'
577-
&& typeof arguments[1] === 'string') {
578-
const element = arguments[0];
579-
const dir = arguments[1];
580-
581-
switch (dir) {
582-
case 'left':
583-
/* falls through */
584-
case 'right':
585-
if (element.scrollWidth > element.clientWidth)
586-
return true;
587-
break;
588-
case 'up':
589-
/* falls through */
590-
case 'down':
591-
if (element.scrollHeight > element.clientHeight)
592-
return true;
593-
break;
594-
}
595-
return false;
596-
}
597-
else {
598-
return false;
599544
}
545+
return false;
600546
}
601547

602548
/* Check whether the scroll of window is down to the end or not */
@@ -659,19 +605,19 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
659605
* Check whether this element is completely visible in this viewport for the arrow direction.
660606
*/
661607
function isEntirelyVisible(element) {
662-
const container = element.getSpatnavContainer();
663608
const rect = element.getBoundingClientRect();
664-
const containerRect = container.getBoundingClientRect();
609+
const containerRect = element.getSpatnavContainer().getBoundingClientRect();
665610

666611
// FIXME: when element is bigger than container?
612+
const entirelyVisible = !((rect.left < containerRect.left) ||
613+
(rect.right > containerRect.right) ||
614+
(rect.top < containerRect.top) ||
615+
(rect.bottom > containerRect.botto));
667616

668-
if (rect.left < containerRect.left) return false;
669-
if (rect.right > containerRect.right) return false;
670-
if (rect.top < containerRect.top) return false;
671-
if (rect.bottom > containerRect.botto) return false;
617+
if(entirelyVisible)
618+
console.log('entirely in the view');
672619

673-
console.log('entirely in the view');
674-
return true;
620+
return entirelyVisible;
675621
}
676622

677623
/* Check the style property of this element whether it's visible or not */
@@ -680,7 +626,7 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
680626
const thisDisplay = window.getComputedStyle(element, null).getPropertyValue('display');
681627
const invisibleStyle = ['hidden', 'collapse'];
682628

683-
return (!includes(invisibleStyle, thisVisibility) && thisDisplay !== 'none');
629+
return (!invisibleStyle.includes(thisVisibility) && thisDisplay !== 'none');
684630
}
685631

686632
/**
@@ -701,12 +647,12 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
701647
const leftBottomElem = document.elementFromPoint(elementRect.left + offsetX, elementRect.bottom - offsetY);
702648
const rightTopElem = document.elementFromPoint(elementRect.right - offsetX, elementRect.top + offsetY);
703649
const rightBottomElem = document.elementFromPoint(elementRect.right - offsetX, elementRect.bottom - offsetY);
704-
if (element === middleElem || element.contains(middleElem)) return true;
705-
if (element === leftTopElem || element.contains(leftTopElem)) return true;
706-
if (element === leftBottomElem || element.contains(leftBottomElem)) return true;
707-
if (element === rightTopElem || element.contains(rightTopElem)) return true;
708-
if (element === rightBottomElem || element.contains(rightBottomElem)) return true;
709-
return false;
650+
651+
return ((element === middleElem || element.contains(middleElem)) ||
652+
(element === leftTopElem || element.contains(leftTopElem)) ||
653+
(element === leftBottomElem || element.contains(leftBottomElem)) ||
654+
(element === rightTopElem || element.contains(rightTopElem)) ||
655+
(element === rightBottomElem || element.contains(rightBottomElem)));
710656
}
711657

712658
/* rect1 is outside of rect2 for the dir */
@@ -953,28 +899,19 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
953899
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
954900
*/
955901
function handlingEditableElement(e) {
902+
const spinnableInputTypes = ['email', 'date', 'month', 'number', 'time', 'week'],
903+
textInputTypes = ['password', 'text', 'search', 'tel', 'url'];
956904
const eventTarget = document.activeElement;
957905
const startPosition = eventTarget.selectionStart;
958906
const endPosition = eventTarget.selectionEnd;
959907
const focusNavigableArrowKey = {'left': false, 'up': false, 'right': false, 'down': false};
960908

961-
if (includes(spinnableInputTypes, eventTarget.getAttribute('type'))) {
962-
switch (e.keyCode) {
963-
case 37: // left keycode
964-
focusNavigableArrowKey.left = false;
965-
break;
966-
case 38: // up keycode
967-
focusNavigableArrowKey.up = true;
968-
break;
969-
case 39: // right keycode
970-
focusNavigableArrowKey.right = false;
971-
break;
972-
case 40: // down keycode
973-
focusNavigableArrowKey.down = true;
974-
break;
975-
}
909+
const dir = ARROW_KEY_CODE[e.keyCode];
910+
if (spinnableInputTypes.includes(eventTarget.getAttribute('type')) &&
911+
(dir === 'up' || dir === 'down')) {
912+
focusNavigableArrowKey[dir] = true;
976913
}
977-
else if (includes(textInputTypes, eventTarget.getAttribute('type'))) {
914+
else if (textInputTypes.includes(eventTarget.getAttribute('type'))) {
978915
if (startPosition === 0) {
979916
focusNavigableArrowKey.left = true;
980917
focusNavigableArrowKey.up = true;
@@ -985,40 +922,15 @@ function focusNavigationHeuristics(spatnavPolyfillOptions) {
985922
}
986923
}
987924
else {
988-
switch (e.keyCode) {
989-
case 37: // left keycode
990-
focusNavigableArrowKey.left = true;
991-
break;
992-
case 38: // up keycode
993-
focusNavigableArrowKey.up = true;
994-
break;
995-
case 39: // right keycode
996-
focusNavigableArrowKey.right = true;
997-
break;
998-
case 40: // down keycode
999-
focusNavigableArrowKey.down = true;
1000-
break;
1001-
}
925+
focusNavigableArrowKey[dir] = true;
1002926
}
1003927

1004928
return focusNavigableArrowKey;
1005929
}
1006930

1007-
/*
1008-
* Nodelist Object Function
1009-
* Whether NodeList includes the element or not
1010-
*/
1011-
function includes(nodelist, element) {
1012-
for (let i = 0; i < nodelist.length; i++) {
1013-
if (nodelist[i] === element) return true;
1014-
}
1015-
return false;
1016-
}
1017-
1018-
1019931
// Use non standard names by default, as per https://www.w3.org/2001/tag/doc/polyfills/#don-t-squat-on-proposed-names-in-speculative-polyfills
1020932
// Allow binding to standard name for testing purposes
1021-
if (typeof spatnavPolyfillOptions == 'object' && spatnavPolyfillOptions.standardName) {
933+
if (typeof spatnavPolyfillOptions === 'object' && spatnavPolyfillOptions.standardName) {
1022934
window.navigate = navigate;
1023935
window.Element.prototype.spatNavSearch = spatNavSearch;
1024936
window.Element.prototype.focusableAreas = focusableAreas;

0 commit comments

Comments
 (0)