From 30bc82f68b6de69a2e456286888824fa0221d4a7 Mon Sep 17 00:00:00 2001
From: Clement Ho <clemmakesapps@gmail.com>
Date: Fri, 1 Jun 2018 16:41:50 +0000
Subject: [PATCH] Revert "Merge branch '46833-sticky-polyfill' into 'master'"

This reverts merge request !19304
---
 .../javascripts/init_changes_dropdown.js      |  6 +-
 app/assets/javascripts/job.js                 |  7 ++
 app/assets/javascripts/lib/utils/sticky.js    | 39 +++++++++
 spec/javascripts/lib/utils/sticky_spec.js     | 79 +++++++++++++++++++
 4 files changed, 128 insertions(+), 3 deletions(-)
 create mode 100644 app/assets/javascripts/lib/utils/sticky.js
 create mode 100644 spec/javascripts/lib/utils/sticky_spec.js

diff --git a/app/assets/javascripts/init_changes_dropdown.js b/app/assets/javascripts/init_changes_dropdown.js
index a9f4829f980c9..09cca1dc7d99d 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 8dfe8aae5b545..611e8200b4de8 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 0000000000000..098afcfa1b494
--- /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 0000000000000..b87c836654d07
--- /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();
+    });
+  });
+});
-- 
GitLab