fix scroll when popstate from a full screen code block (#19674)
This commit is contained in:
parent
4632c6bbf4
commit
5fe3a04287
2 changed files with 127 additions and 2 deletions
|
|
@ -0,0 +1,106 @@
|
|||
const importModule = () => import('@utilities/codeFullscreenModeSwitcher');
|
||||
|
||||
describe('CodeFullScreenModeSwitcher Utility', () => {
|
||||
let addFullScreenModeControl, getFullScreenModeStatus;
|
||||
let onPressEscape, onPopstate;
|
||||
|
||||
const getFullScreenElements = () =>
|
||||
['.js-fullscreen-code.is-open', '.js-code-highlight.is-fullscreen'].map(
|
||||
(selector) => document.body.querySelector(selector),
|
||||
);
|
||||
|
||||
const testFullScreenElements = ({ exists }) => {
|
||||
for (const element of getFullScreenElements()) {
|
||||
if (exists) expect(element).not.toBeNull();
|
||||
else expect(element).toBeNull();
|
||||
}
|
||||
};
|
||||
|
||||
const testNonFullScreen = () => {
|
||||
expect(getFullScreenModeStatus()).toBe(false);
|
||||
testFullScreenElements({ exists: false });
|
||||
expect(document.body.style.overflow).toBe('');
|
||||
};
|
||||
|
||||
const testFullScreen = () => {
|
||||
expect(getFullScreenModeStatus()).toBe(true);
|
||||
testFullScreenElements({ exists: true });
|
||||
expect(document.body.style.overflow).toBe('hidden');
|
||||
};
|
||||
|
||||
const getEnterFullScreenButtons = () =>
|
||||
document.getElementsByClassName('js-fullscreen-code-action');
|
||||
|
||||
beforeAll(() => {
|
||||
global.scrollTo = jest.fn();
|
||||
|
||||
document.body.innerHTML = `
|
||||
<div class="js-code-highlight">
|
||||
<div class="js-fullscreen-code-action"><div>
|
||||
</div>
|
||||
<div class="js-fullscreen-code"></div>
|
||||
`;
|
||||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
({ addFullScreenModeControl, getFullScreenModeStatus } =
|
||||
await importModule());
|
||||
addFullScreenModeControl(getEnterFullScreenButtons());
|
||||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
// eventListener functions
|
||||
({ onPressEscape, onPopstate } = await importModule());
|
||||
});
|
||||
|
||||
it('starts in non-fullscreen mode', testNonFullScreen);
|
||||
|
||||
it('enters fullscreen mode on click', () => {
|
||||
const goFullScreenButtons = getEnterFullScreenButtons();
|
||||
const spyDoc = jest.spyOn(document.body, 'addEventListener');
|
||||
const spyWindow = jest.spyOn(window, 'addEventListener');
|
||||
|
||||
goFullScreenButtons[0].click();
|
||||
|
||||
testFullScreen();
|
||||
expect(spyDoc).toHaveBeenCalledWith('keyup', onPressEscape);
|
||||
expect(spyWindow).toHaveBeenCalledWith('popstate', onPopstate);
|
||||
});
|
||||
|
||||
it('exits fullscreen mode on Escape key', () => {
|
||||
const spyDocRemove = jest.spyOn(document.body, 'removeEventListener');
|
||||
const spyWindowRemove = jest.spyOn(window, 'removeEventListener');
|
||||
|
||||
testFullScreen();
|
||||
document.body.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
|
||||
testNonFullScreen();
|
||||
|
||||
expect(spyDocRemove).toHaveBeenCalledWith('keyup', onPressEscape);
|
||||
expect(spyWindowRemove).toHaveBeenCalledWith('popstate', onPopstate);
|
||||
});
|
||||
|
||||
it('re-enters fullscreen mode on click', () => {
|
||||
const goFullScreenButtons = getEnterFullScreenButtons();
|
||||
const spyDoc = jest.spyOn(document.body, 'addEventListener');
|
||||
const spyWindow = jest.spyOn(window, 'addEventListener');
|
||||
|
||||
testNonFullScreen();
|
||||
goFullScreenButtons[0].click();
|
||||
testFullScreen();
|
||||
|
||||
expect(spyDoc).toHaveBeenCalledWith('keyup', onPressEscape);
|
||||
expect(spyWindow).toHaveBeenCalledWith('popstate', onPopstate);
|
||||
});
|
||||
|
||||
it('exits fullscreen mode on popstate event', () => {
|
||||
const spyDocRemove = jest.spyOn(document.body, 'removeEventListener');
|
||||
const spyWindowRemove = jest.spyOn(window, 'removeEventListener');
|
||||
|
||||
testFullScreen();
|
||||
window.dispatchEvent(new PopStateEvent('popstate', { state: { key: '' } }));
|
||||
testNonFullScreen();
|
||||
|
||||
expect(spyDocRemove).toHaveBeenCalledWith('keyup', onPressEscape);
|
||||
expect(spyWindowRemove).toHaveBeenCalledWith('popstate', onPopstate);
|
||||
});
|
||||
});
|
||||
|
|
@ -4,6 +4,10 @@ const fullScreenWindow =
|
|||
document.getElementsByClassName('js-fullscreen-code')[0];
|
||||
const { body } = document;
|
||||
|
||||
export function getFullScreenModeStatus() {
|
||||
return isFullScreenModeCodeOn;
|
||||
}
|
||||
|
||||
function setAfterFullScreenScrollPosition() {
|
||||
window.scrollTo(0, screenScroll);
|
||||
}
|
||||
|
|
@ -12,7 +16,7 @@ function getBeforeFullScreenScrollPosition() {
|
|||
screenScroll = window.scrollY;
|
||||
}
|
||||
|
||||
function onPressEscape(event) {
|
||||
export function onPressEscape(event) {
|
||||
if (event.key == 'Escape') {
|
||||
fullScreenModeControl(event);
|
||||
}
|
||||
|
|
@ -26,6 +30,18 @@ function listenToKeyboardForEscape(listen) {
|
|||
}
|
||||
}
|
||||
|
||||
export function onPopstate() {
|
||||
fullScreenModeControl();
|
||||
}
|
||||
|
||||
function listenToWindowForPopstate(listen) {
|
||||
if (listen) {
|
||||
window.addEventListener('popstate', onPopstate);
|
||||
} else {
|
||||
window.removeEventListener('popstate', onPopstate);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleOverflowForDocument(overflow) {
|
||||
if (overflow) {
|
||||
body.style.overflow = 'hidden';
|
||||
|
|
@ -51,7 +67,7 @@ function removeFullScreenModeControl(elements) {
|
|||
}
|
||||
|
||||
function fullScreenModeControl(event) {
|
||||
const codeBlock = event.currentTarget.closest('.js-code-highlight')
|
||||
const codeBlock = event?.currentTarget.closest('.js-code-highlight')
|
||||
? event.currentTarget.closest('.js-code-highlight').cloneNode(true)
|
||||
: null;
|
||||
const codeBlockControls = codeBlock
|
||||
|
|
@ -62,6 +78,7 @@ function fullScreenModeControl(event) {
|
|||
toggleOverflowForDocument(false);
|
||||
setAfterFullScreenScrollPosition();
|
||||
listenToKeyboardForEscape(false);
|
||||
listenToWindowForPopstate(false);
|
||||
removeFullScreenModeControl(codeBlockControls);
|
||||
|
||||
fullScreenWindow.classList.remove('is-open');
|
||||
|
|
@ -72,6 +89,8 @@ function fullScreenModeControl(event) {
|
|||
toggleOverflowForDocument(true);
|
||||
getBeforeFullScreenScrollPosition();
|
||||
listenToKeyboardForEscape(true);
|
||||
listenToWindowForPopstate(true);
|
||||
|
||||
codeBlock.classList.add('is-fullscreen');
|
||||
fullScreenWindow.appendChild(codeBlock);
|
||||
fullScreenWindow.classList.add('is-open');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue