Commit e83f953e authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'psi-no-note-scroll' into 'master'

Limit scrollToTargetOnResize to note hashes

See merge request gitlab-org/gitlab!81192
parents d5aa7eb7 de5f5aa0
...@@ -10,22 +10,30 @@ export function createResizeObserver() { ...@@ -10,22 +10,30 @@ export function createResizeObserver() {
}); });
} }
// watches for change in size of a container element (e.g. for lazy-loaded images) /**
// and scroll the target element to the top of the content area * Watches for change in size of a container element (e.g. for lazy-loaded images)
// stop watching after any user input. So if user opens sidebar or manually * and scrolls the target note to the top of the content area.
// scrolls the page we don't hijack their scroll position * Stops watching after any user input. So if user opens sidebar or manually
* scrolls the page we don't hijack their scroll position
*
* @param {Object} options
* @param {string} options.targetId - id of element to scroll to
* @param {string} options.container - Selector of element containing target
*
* @return {ResizeObserver|null} - ResizeObserver instance if target looks like a note DOM ID
*/
export function scrollToTargetOnResize({ export function scrollToTargetOnResize({
target = window.location.hash, targetId = window.location.hash.slice(1),
container = '#content-body', container = '#content-body',
} = {}) { } = {}) {
if (!target) return null; if (!targetId) return null;
const ro = createResizeObserver(); const ro = createResizeObserver();
const containerEl = document.querySelector(container); const containerEl = document.querySelector(container);
let interactionListenersAdded = false; let interactionListenersAdded = false;
function keepTargetAtTop() { function keepTargetAtTop() {
const anchorEl = document.querySelector(target); const anchorEl = document.getElementById(targetId);
if (!anchorEl) return; if (!anchorEl) return;
......
...@@ -19,16 +19,11 @@ describe('ResizeObserver Utility', () => { ...@@ -19,16 +19,11 @@ describe('ResizeObserver Utility', () => {
jest.spyOn(document.documentElement, 'scrollTo'); jest.spyOn(document.documentElement, 'scrollTo');
setFixtures(`<div id="content-body"><div class="target">element to scroll to</div></div>`); setFixtures(`<div id="content-body"><div id="note_1234">note to scroll to</div></div>`);
const target = document.querySelector('.target'); const target = document.querySelector('#note_1234');
jest.spyOn(target, 'getBoundingClientRect').mockReturnValue({ top: 200 }); jest.spyOn(target, 'getBoundingClientRect').mockReturnValue({ top: 200 });
observer = scrollToTargetOnResize({
target: '.target',
container: '#content-body',
});
}); });
afterEach(() => { afterEach(() => {
...@@ -38,21 +33,22 @@ describe('ResizeObserver Utility', () => { ...@@ -38,21 +33,22 @@ describe('ResizeObserver Utility', () => {
describe('Observer behavior', () => { describe('Observer behavior', () => {
it('returns null for empty target', () => { it('returns null for empty target', () => {
observer = scrollToTargetOnResize({ observer = scrollToTargetOnResize({
target: '', targetId: '',
container: '#content-body', container: '#content-body',
}); });
expect(observer).toBe(null); expect(observer).toBe(null);
}); });
it('returns ResizeObserver instance', () => { it('does not scroll if target does not exist', () => {
expect(observer).toBeInstanceOf(ResizeObserver); observer = scrollToTargetOnResize({
}); targetId: 'some_imaginary_id',
container: '#content-body',
});
it('scrolls body so anchor is just below sticky header (contentTop)', () => {
triggerResize(); triggerResize();
expect(document.documentElement.scrollTo).toHaveBeenCalledWith({ top: 110 }); expect(document.documentElement.scrollTo).not.toHaveBeenCalled();
}); });
const interactionEvents = ['mousedown', 'touchstart', 'keydown', 'wheel']; const interactionEvents = ['mousedown', 'touchstart', 'keydown', 'wheel'];
...@@ -64,5 +60,24 @@ describe('ResizeObserver Utility', () => { ...@@ -64,5 +60,24 @@ describe('ResizeObserver Utility', () => {
expect(document.documentElement.scrollTo).not.toHaveBeenCalledWith(); expect(document.documentElement.scrollTo).not.toHaveBeenCalledWith();
}); });
describe('with existing target', () => {
beforeEach(() => {
observer = scrollToTargetOnResize({
targetId: 'note_1234',
container: '#content-body',
});
});
it('returns ResizeObserver instance', () => {
expect(observer).toBeInstanceOf(ResizeObserver);
});
it('scrolls body so anchor is just below sticky header (contentTop)', () => {
triggerResize();
expect(document.documentElement.scrollTo).toHaveBeenCalledWith({ top: 110 });
});
});
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment