Commit b187a3f2 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'changes-bar-dynamic-placeholder' into 'master'

Dynamically create offset for sticky bar

See merge request gitlab-org/gitlab-ce!14280
parents 178ae69b 1544bc32
export const isSticky = (el, scrollY, stickyTop) => { export const createPlaceholder = () => {
const placeholder = document.createElement('div');
placeholder.classList.add('sticky-placeholder');
return placeholder;
};
export const isSticky = (el, scrollY, stickyTop, insertPlaceholder) => {
const top = Math.floor(el.offsetTop - scrollY); const top = Math.floor(el.offsetTop - scrollY);
if (top <= stickyTop) { if (top <= stickyTop && !el.classList.contains('is-stuck')) {
const placeholder = insertPlaceholder ? createPlaceholder() : null;
const heightBefore = el.offsetHeight;
el.classList.add('is-stuck'); el.classList.add('is-stuck');
} else {
if (insertPlaceholder) {
el.parentNode.insertBefore(placeholder, el.nextElementSibling);
placeholder.style.height = `${heightBefore - el.offsetHeight}px`;
}
} else if (top > stickyTop && el.classList.contains('is-stuck')) {
el.classList.remove('is-stuck'); el.classList.remove('is-stuck');
if (insertPlaceholder && el.nextElementSibling && el.nextElementSibling.classList.contains('sticky-placeholder')) {
el.nextElementSibling.remove();
}
} }
}; };
export default (el) => { export default (el, insertPlaceholder = true) => {
if (!el) return; if (!el) return;
const computedStyle = window.getComputedStyle(el); const computedStyle = window.getComputedStyle(el);
...@@ -17,7 +37,7 @@ export default (el) => { ...@@ -17,7 +37,7 @@ export default (el) => {
const stickyTop = parseInt(computedStyle.top, 10); const stickyTop = parseInt(computedStyle.top, 10);
document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop), { document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), {
passive: true, passive: true,
}); });
}; };
...@@ -451,7 +451,7 @@ ...@@ -451,7 +451,7 @@
} }
.files { .files {
margin-top: -1px; margin-top: 1px;
.diff-file:last-child { .diff-file:last-child {
margin-bottom: 0; margin-bottom: 0;
...@@ -586,11 +586,6 @@ ...@@ -586,11 +586,6 @@
top: 76px; top: 76px;
} }
+ .files,
+ .alert {
margin-top: 1px;
}
&:not(.is-stuck) .diff-stats-additions-deletions-collapsed { &:not(.is-stuck) .diff-stats-additions-deletions-collapsed {
display: none; display: none;
} }
...@@ -605,11 +600,6 @@ ...@@ -605,11 +600,6 @@
.inline-parallel-buttons { .inline-parallel-buttons {
display: none; display: none;
} }
+ .files,
+ .alert {
margin-top: 32px;
}
} }
} }
} }
......
...@@ -15,3 +15,9 @@ ...@@ -15,3 +15,9 @@
-ms-animation: none !important; -ms-animation: none !important;
animation: none !important; animation: none !important;
} }
// Disable sticky changes bar for tests
.diff-files-changed {
position: relative !important;
top: 0 !important;
}
import { isSticky } from '~/lib/utils/sticky'; import { isSticky } from '~/lib/utils/sticky';
describe('sticky', () => { describe('sticky', () => {
const el = { let el;
offsetTop: 0,
classList: {},
};
beforeEach(() => { beforeEach(() => {
el.offsetTop = 0; document.body.innerHTML += `
el.classList.add = jasmine.createSpy('spy'); <div class="parent">
el.classList.remove = jasmine.createSpy('spy'); <div id="js-sticky"></div>
</div>
`;
el = document.getElementById('js-sticky');
}); });
describe('classList.remove', () => { afterEach(() => {
it('does not call classList.remove when stuck', () => { el.parentNode.remove();
isSticky(el, 0, 0); });
describe('when stuck', () => {
it('does not remove is-stuck class', () => {
isSticky(el, 0, el.offsetTop);
isSticky(el, 0, el.offsetTop);
expect( expect(
el.classList.remove, el.classList.contains('is-stuck'),
).not.toHaveBeenCalled(); ).toBeTruthy();
}); });
it('calls classList.remove when not stuck', () => { it('adds is-stuck class', () => {
el.offsetTop = 10; isSticky(el, 0, el.offsetTop);
isSticky(el, 0, 0);
expect( expect(
el.classList.remove, el.classList.contains('is-stuck'),
).toHaveBeenCalledWith('is-stuck'); ).toBeTruthy();
});
it('inserts placeholder element', () => {
isSticky(el, 0, el.offsetTop, true);
expect(
document.querySelector('.sticky-placeholder'),
).not.toBeNull();
}); });
}); });
describe('classList.add', () => { describe('when not stuck', () => {
it('calls classList.add when stuck', () => { it('removes is-stuck class', () => {
spyOn(el.classList, 'remove').and.callThrough();
isSticky(el, 0, el.offsetTop);
isSticky(el, 0, 0); isSticky(el, 0, 0);
expect( expect(
el.classList.add, el.classList.remove,
).toHaveBeenCalledWith('is-stuck'); ).toHaveBeenCalledWith('is-stuck');
expect(
el.classList.contains('is-stuck'),
).toBeFalsy();
}); });
it('does not call classList.add when not stuck', () => { it('does not add is-stuck class', () => {
el.offsetTop = 10;
isSticky(el, 0, 0); isSticky(el, 0, 0);
expect( expect(
el.classList.add, el.classList.contains('is-stuck'),
).not.toHaveBeenCalled(); ).toBeFalsy();
});
it('removes placeholder', () => {
isSticky(el, 0, el.offsetTop, true);
isSticky(el, 0, 0, true);
expect(
document.querySelector('.sticky-placeholder'),
).toBeNull();
}); });
}); });
}); });
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