-
Notifications
You must be signed in to change notification settings - Fork 776
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
89b8bab
commit d55f3cd
Showing
6 changed files
with
303 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/** | ||
* Return the scroll position of scrollable elements | ||
*/ | ||
function getScroll (elm) { | ||
const style = window.getComputedStyle(elm); | ||
const visibleOverflowY = style.getPropertyValue('overflow-y') === 'visible'; | ||
const visibleOverflowX = style.getPropertyValue('overflow-x') === 'visible'; | ||
|
||
if (// See if the element hides overflowing content | ||
(!visibleOverflowY && elm.scrollHeight > elm.clientHeight) || | ||
(!visibleOverflowX && elm.scrollWidth > elm.clientWidth) | ||
) { | ||
return { elm, top: elm.scrollTop, left: elm.scrollLeft }; | ||
} | ||
} | ||
|
||
/** | ||
* set the scroll position of an element | ||
*/ | ||
function setScroll (elm, top, left) { | ||
if (elm === window) { | ||
return elm.scroll(top, left); | ||
} else { | ||
elm.scrollTop = top; | ||
elm.scrollLeft = left; | ||
} | ||
} | ||
|
||
/** | ||
* Create an array scroll positions from descending elements | ||
*/ | ||
function getElmScrollRecursive (root) { | ||
return Array.from(root.children).reduce((scrolls, elm) => { | ||
const scroll = getScroll(elm); | ||
if (scroll) { | ||
scrolls.push(scroll); | ||
} | ||
return scrolls.concat(getElmScrollRecursive(elm)); | ||
}, []); | ||
} | ||
|
||
/** | ||
* Get the scroll position of all scrollable elements in a page | ||
*/ | ||
axe.utils.getScrollState = function getScrollState (win = window) { | ||
const root = win.document.documentElement; | ||
const windowScroll = [(win.pageXOffset !== undefined ? { | ||
elm: win, | ||
top: win.pageYOffset, | ||
left: win.pageXOffset | ||
} : { | ||
elm: root, | ||
top: root.scrollTop, | ||
left: root.scrollLeft | ||
})]; | ||
|
||
return windowScroll.concat( | ||
getElmScrollRecursive(document.body) | ||
); | ||
}; | ||
|
||
/** | ||
* set the scroll position of all items in the scrollState array | ||
*/ | ||
axe.utils.setScrollState = function setScrollState (scrollState) { | ||
scrollState.forEach( | ||
({ elm, top, left }) => setScroll(elm, top, left) | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
describe('axe.utils.getScrollState', function () { | ||
'use strict'; | ||
var mockWin; | ||
var getScrollState = axe.utils.getScrollState; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
|
||
beforeEach(function () { | ||
mockWin = { | ||
pageXOffset: 1, | ||
pageYOffset: 3, | ||
document: { | ||
documentElement: { | ||
children: [], | ||
scrollTop: 3, | ||
scrollHeight: 4 | ||
} | ||
}, | ||
body: { children: [] } | ||
}; | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should be a function', function () { | ||
assert.isFunction(getScrollState); | ||
}); | ||
|
||
it('takes the window object as an optional argument', function () { | ||
assert.deepEqual( | ||
getScrollState(), | ||
getScrollState(window) | ||
); | ||
}); | ||
|
||
it('returns the window as the first item, if pageXOffset is supported', function () { | ||
assert.deepEqual( | ||
getScrollState(mockWin)[0], | ||
{ | ||
elm: mockWin, | ||
top: mockWin.pageYOffset, | ||
left: mockWin.pageXOffset | ||
} | ||
); | ||
}); | ||
|
||
it('returns the html as the first item, if pageXOffset is not supported', function () { | ||
mockWin.pageYOffset = undefined; | ||
mockWin.pageXOffset = undefined; | ||
var html = mockWin.document.documentElement; | ||
|
||
assert.deepEqual( | ||
getScrollState(mockWin)[0], | ||
{ | ||
elm: html, | ||
top: html.scrollTop, | ||
left: html.scrollLeft | ||
} | ||
); | ||
}); | ||
|
||
it('grabs scrollTop and scrollLeft from all descendants of body', function () { | ||
fixture.innerHTML = | ||
'<div style="overflow:auto; height: 50px" id="tgt1">' + | ||
'<div style="height: 100px"> Han Solo </div>' + | ||
'<div style="overflow: hidden; height: 50px" id="tgt2">' + | ||
'<div style="height: 100px"> Chewbacca </div>' + | ||
'</div>' + | ||
'</div>'; | ||
|
||
var tgt1 = document.getElementById('tgt1'); | ||
var tgt2 = document.getElementById('tgt2'); | ||
tgt1.scrollTop = 10; | ||
tgt2.scrollTop = 20; | ||
|
||
var scrollState = getScrollState(); | ||
|
||
assert.deepEqual( | ||
scrollState.find(function (scroll) { return scroll.elm === tgt1; }), | ||
{ elm: tgt1, top: 10, left: 0 } | ||
); | ||
assert.deepEqual( | ||
scrollState.find(function (scroll) { return scroll.elm === tgt2; }), | ||
{ elm: tgt2, top: 20, left: 0 } | ||
); | ||
}); | ||
|
||
it('ignores elements with overflow visible', function () { | ||
fixture.innerHTML = | ||
'<div style="overflow:visible; height: 50px" id="tgt1">' + | ||
'<div style="height: 100px" id="tgt2"> Han Solo </div>' + | ||
'</div>'; | ||
|
||
var tgt1 = document.getElementById('tgt1'); | ||
var tgt2 = document.getElementById('tgt2'); | ||
var scrollState = getScrollState(); | ||
|
||
assert.isUndefined( | ||
scrollState.find(function (scroll) { return scroll.elm === tgt1; }) | ||
); | ||
assert.isUndefined( | ||
scrollState.find(function (scroll) { return scroll.elm === tgt2; }) | ||
); | ||
}); | ||
|
||
it('ignores elements that do not overflow', function () { | ||
fixture.innerHTML = | ||
'<div style="overflow:auto; height: 300px" id="tgt1">' + | ||
'<div style="height: 100px"> Han Solo </div>' + | ||
'<div style="overflow: hidden; height: 150px" id="tgt2">' + | ||
'<div style="height: 100px"> Chewbacca </div>' + | ||
'</div>' + | ||
'</div>'; | ||
|
||
var tgt1 = document.getElementById('tgt1'); | ||
var tgt2 = document.getElementById('tgt2'); | ||
var scrollState = getScrollState(); | ||
|
||
assert.isUndefined( | ||
scrollState.find(function (scroll) { return scroll.elm === tgt1; }) | ||
); | ||
assert.isUndefined( | ||
scrollState.find(function (scroll) { return scroll.elm === tgt2; }) | ||
); | ||
}); | ||
}); | ||
|
||
describe('axe.utils.setScrollState', function () { | ||
'use strict'; | ||
var setScrollState = axe.utils.setScrollState; | ||
|
||
var fixture = document.getElementById('fixture'); | ||
afterEach(function () { | ||
fixture.innerHTML = ''; | ||
}); | ||
|
||
it('should be a function', function () { | ||
assert.isFunction(setScrollState); | ||
}); | ||
|
||
it('sets scrollTop and scrollLeft for regular nodes', function () { | ||
var elm1 = {}, elm2 = {}; | ||
setScrollState([ | ||
{ elm: elm1, top: 10, left: 20 }, | ||
{ elm: elm2, top: 30, left: 40 }, | ||
]); | ||
|
||
assert.deepEqual(elm1, { scrollTop: 10, scrollLeft: 20 }); | ||
assert.deepEqual(elm2, { scrollTop: 30, scrollLeft: 40 }); | ||
}); | ||
|
||
it('calls scroll() for the window element', function () { | ||
var called; | ||
var winScroll = window.scroll; | ||
window.scroll = function (top, left) { | ||
called = { top: top, left: left }; | ||
}; | ||
setScrollState([ | ||
{ elm: window, top: 10, left: 20 } | ||
]); | ||
assert.deepEqual(called, { top: 10, left: 20 }); | ||
window.scroll = winScroll; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,25 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<title>O hai</title> | ||
|
||
<div style=" | ||
height: 50px; | ||
width: 50px; | ||
border: solid 1px black; | ||
overflow: auto; | ||
"> | ||
<p>foofoofoofoofoofoo</p> | ||
<p>foofoofoofoofoofoo</p> | ||
<p>foofoofoofoofoofoo</p> | ||
<p>foofoofoofoofoofoo</p> | ||
<p>foofoofoofoofoofoo</p> | ||
</div> | ||
|
||
<script src="/axe.js"></script> | ||
<div id="dupe"></div> | ||
<div id="dupe"></div> | ||
<script> | ||
|
||
window.addEventListener('load' , function () { | ||
axe.a11yCheck(document, {}, function (res) { | ||
console.log(res); | ||
}); | ||
axe.a11yCheck(document, { restoreScroll: true }, function (res) { | ||
console.log(res); | ||
}); | ||
}) | ||
|
||
</script> | ||
</script> |