summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClement Ho <clemmakesapps@gmail.com>2018-06-01 17:22:36 +0000
committerClement Ho <clemmakesapps@gmail.com>2018-06-01 17:22:36 +0000
commit160cc6cd7b0218cdd1e210c4133fd469ffacf656 (patch)
tree029173f59928bf5fe9efb143f380eb874263bac2
parentaa5e61d510885ac18cb06d96337dd4451334ffc5 (diff)
parent30bc82f68b6de69a2e456286888824fa0221d4a7 (diff)
downloadgitlab-ce-160cc6cd7b0218cdd1e210c4133fd469ffacf656.tar.gz
Merge branch 'revert-c640e579' into 'master'
Revert "Merge branch '46833-sticky-polyfill' into 'master'" See merge request gitlab-org/gitlab-ce!19322
-rw-r--r--app/assets/javascripts/init_changes_dropdown.js6
-rw-r--r--app/assets/javascripts/job.js7
-rw-r--r--app/assets/javascripts/lib/utils/sticky.js39
-rw-r--r--spec/javascripts/lib/utils/sticky_spec.js79
4 files changed, 128 insertions, 3 deletions
diff --git a/app/assets/javascripts/init_changes_dropdown.js b/app/assets/javascripts/init_changes_dropdown.js
index a9f4829f980..09cca1dc7d9 100644
--- a/app/assets/javascripts/init_changes_dropdown.js
+++ b/app/assets/javascripts/init_changes_dropdown.js
@@ -1,8 +1,8 @@
import $ from 'jquery';
-import StickyFill from 'stickyfilljs';
+import stickyMonitor from './lib/utils/sticky';
-export default () => {
- StickyFill.add(document.querySelector('.js-diff-files-changed'));
+export default (stickyTop) => {
+ stickyMonitor(document.querySelector('.js-diff-files-changed'), stickyTop);
$('.js-diff-stats-dropdown').glDropdown({
filterable: true,
diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js
index 8dfe8aae5b5..611e8200b4d 100644
--- a/app/assets/javascripts/job.js
+++ b/app/assets/javascripts/job.js
@@ -80,6 +80,13 @@ export default class Job {
}
initAffixTopArea() {
+ /**
+ If the browser does not support position sticky, it returns the position as static.
+ If the browser does support sticky, then we allow the browser to handle it, if not
+ then we use a polyfill
+ */
+ if (this.$topBar.css('position') !== 'static') return;
+
StickyFill.add(this.$topBar);
}
diff --git a/app/assets/javascripts/lib/utils/sticky.js b/app/assets/javascripts/lib/utils/sticky.js
new file mode 100644
index 00000000000..098afcfa1b4
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/sticky.js
@@ -0,0 +1,39 @@
+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);
+
+ if (top <= stickyTop && !el.classList.contains('is-stuck')) {
+ const placeholder = insertPlaceholder ? createPlaceholder() : null;
+ const heightBefore = el.offsetHeight;
+
+ el.classList.add('is-stuck');
+
+ 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');
+
+ if (insertPlaceholder && el.nextElementSibling && el.nextElementSibling.classList.contains('sticky-placeholder')) {
+ el.nextElementSibling.remove();
+ }
+ }
+};
+
+export default (el, stickyTop, insertPlaceholder = true) => {
+ if (!el) return;
+
+ if (typeof CSS === 'undefined' || !(CSS.supports('(position: -webkit-sticky) or (position: sticky)'))) return;
+
+ document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop, insertPlaceholder), {
+ passive: true,
+ });
+};
diff --git a/spec/javascripts/lib/utils/sticky_spec.js b/spec/javascripts/lib/utils/sticky_spec.js
new file mode 100644
index 00000000000..b87c836654d
--- /dev/null
+++ b/spec/javascripts/lib/utils/sticky_spec.js
@@ -0,0 +1,79 @@
+import { isSticky } from '~/lib/utils/sticky';
+
+describe('sticky', () => {
+ let el;
+
+ beforeEach(() => {
+ document.body.innerHTML += `
+ <div class="parent">
+ <div id="js-sticky"></div>
+ </div>
+ `;
+
+ el = document.getElementById('js-sticky');
+ });
+
+ afterEach(() => {
+ el.parentNode.remove();
+ });
+
+ describe('when stuck', () => {
+ it('does not remove is-stuck class', () => {
+ isSticky(el, 0, el.offsetTop);
+ isSticky(el, 0, el.offsetTop);
+
+ expect(
+ el.classList.contains('is-stuck'),
+ ).toBeTruthy();
+ });
+
+ it('adds is-stuck class', () => {
+ isSticky(el, 0, el.offsetTop);
+
+ expect(
+ el.classList.contains('is-stuck'),
+ ).toBeTruthy();
+ });
+
+ it('inserts placeholder element', () => {
+ isSticky(el, 0, el.offsetTop, true);
+
+ expect(
+ document.querySelector('.sticky-placeholder'),
+ ).not.toBeNull();
+ });
+ });
+
+ describe('when not stuck', () => {
+ it('removes is-stuck class', () => {
+ spyOn(el.classList, 'remove').and.callThrough();
+
+ isSticky(el, 0, el.offsetTop);
+ isSticky(el, 0, 0);
+
+ expect(
+ el.classList.remove,
+ ).toHaveBeenCalledWith('is-stuck');
+ expect(
+ el.classList.contains('is-stuck'),
+ ).toBeFalsy();
+ });
+
+ it('does not add is-stuck class', () => {
+ isSticky(el, 0, 0);
+
+ expect(
+ el.classList.contains('is-stuck'),
+ ).toBeFalsy();
+ });
+
+ it('removes placeholder', () => {
+ isSticky(el, 0, el.offsetTop, true);
+ isSticky(el, 0, 0, true);
+
+ expect(
+ document.querySelector('.sticky-placeholder'),
+ ).toBeNull();
+ });
+ });
+});