From fbd09871ca7003242053fbca10d9c0e96e7a799d Mon Sep 17 00:00:00 2001
From: Bryce Johnson <bryce@gitlab.com>
Date: Fri, 13 Jan 2017 16:54:16 -0500
Subject: [PATCH] Remove turbolinks.

---
 Gemfile                                       |  1 -
 Gemfile.lock                                  |  3 --
 app/assets/javascripts/admin.js               |  5 +-
 app/assets/javascripts/application.js         |  4 +-
 app/assets/javascripts/breakpoints.js         |  1 +
 app/assets/javascripts/build.js               |  3 +-
 .../filtered_search_dropdown_manager.js.es6   |  4 +-
 .../filtered_search_manager.js.es6            | 10 ++--
 app/assets/javascripts/gl_dropdown.js         |  3 +-
 app/assets/javascripts/issuable.js.es6        |  5 +-
 .../lib/utils/bootstrap_linked_tabs.js.es6    |  1 -
 .../{url_utility.js => url_utility.js.es6}    |  6 +++
 app/assets/javascripts/line_highlighter.js    |  1 -
 app/assets/javascripts/logo.js                |  9 +---
 .../javascripts/merge_request_tabs.js.es6     |  3 +-
 .../javascripts/merge_request_widget.js.es6   |  5 +-
 app/assets/javascripts/project.js             |  3 +-
 app/assets/javascripts/project_import.js      |  3 +-
 app/assets/javascripts/render_gfm.js          |  2 +-
 app/assets/javascripts/shortcuts.js           |  3 +-
 app/assets/javascripts/shortcuts_issuable.js  |  3 +-
 app/assets/javascripts/sidebar.js.es6         |  2 +-
 app/assets/javascripts/smart_interval.js.es6  |  5 +-
 app/assets/javascripts/todos.js.es6           |  7 ++-
 app/assets/javascripts/tree.js                |  6 +--
 app/assets/javascripts/user_tabs.js.es6       |  1 -
 .../javascripts/vue_pagination/index.js.es6   |  4 +-
 .../vue_pipelines_index/pipelines.js.es6      |  4 +-
 .../vue_realtime_listener/index.js.es6        |  4 +-
 app/assets/stylesheets/framework.scss         |  1 -
 .../stylesheets/framework/progress.scss       |  5 --
 app/helpers/javascript_helper.rb              |  2 +-
 .../devise/shared/_omniauth_box.html.haml     |  2 +-
 app/views/import/bitbucket/status.html.haml   |  2 +-
 app/views/layouts/_head.html.haml             |  2 +
 app/views/layouts/application.html.haml       |  3 --
 app/views/profiles/accounts/show.html.haml    |  2 +-
 .../projects/merge_requests/_show.html.haml   |  8 +--
 app/views/projects/new.html.haml              |  2 +-
 app/views/shared/issuable/_filter.html.haml   |  2 +-
 ...ipate-obstacles-to-removing-turbolinks.yml |  4 ++
 features/steps/project/merge_requests.rb      |  1 +
 spec/javascripts/behaviors/autosize_spec.js   |  2 +-
 .../behaviors/requires_input_spec.js          |  6 ---
 .../bootstrap_linked_tabs_spec.js.es6         |  1 -
 spec/javascripts/build_spec.js.es6            |  7 ++-
 spec/javascripts/gl_dropdown_spec.js.es6      |  7 ++-
 spec/javascripts/issuable_spec.js.es6         | 17 +++----
 spec/javascripts/merge_request_tabs_spec.js   |  1 -
 spec/javascripts/search_autocomplete_spec.js  |  2 -
 spec/javascripts/smart_interval_spec.js.es6   |  2 +-
 spec/javascripts/spec_helper.js               |  1 -
 .../assets/javascripts/jquery.turbolinks.js   | 49 -------------------
 53 files changed, 81 insertions(+), 161 deletions(-)
 rename app/assets/javascripts/lib/utils/{url_utility.js => url_utility.js.es6} (94%)
 delete mode 100644 app/assets/stylesheets/framework/progress.scss
 create mode 100644 changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml
 delete mode 100644 vendor/assets/javascripts/jquery.turbolinks.js

diff --git a/Gemfile b/Gemfile
index dd7c93c5a75..62064fa82b6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -222,7 +222,6 @@ gem 'chronic_duration', '~> 0.10.6'
 gem 'sass-rails', '~> 5.0.6'
 gem 'coffee-rails', '~> 4.1.0'
 gem 'uglifier', '~> 2.7.2'
-gem 'gitlab-turbolinks-classic', '~> 2.5', '>= 2.5.6'
 
 gem 'addressable',        '~> 2.3.8'
 gem 'bootstrap-sass',     '~> 3.3.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 3b207d19d1f..6db54b77979 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -266,8 +266,6 @@ GEM
       mime-types (>= 1.16, < 3)
       posix-spawn (~> 0.3)
     gitlab-markup (1.5.1)
-    gitlab-turbolinks-classic (2.5.6)
-      coffee-rails
     gitlab_omniauth-ldap (1.2.1)
       net-ldap (~> 0.9)
       omniauth (~> 1.0)
@@ -891,7 +889,6 @@ DEPENDENCIES
   github-linguist (~> 4.7.0)
   gitlab-flowdock-git-hook (~> 1.0.1)
   gitlab-markup (~> 1.5.1)
-  gitlab-turbolinks-classic (~> 2.5, >= 2.5.6)
   gitlab_omniauth-ldap (~> 1.2.1)
   gollum-lib (~> 4.2)
   gollum-rugged_adapter (~> 0.4.2)
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
index 993f427c9fb..424dc719c78 100644
--- a/app/assets/javascripts/admin.js
+++ b/app/assets/javascripts/admin.js
@@ -1,5 +1,4 @@
 /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, max-len */
-/* global Turbolinks */
 
 (function() {
   this.Admin = (function() {
@@ -42,10 +41,10 @@
         return $('.change-owner-link').show();
       });
       $('li.project_member').bind('ajax:success', function() {
-        return Turbolinks.visit(location.href);
+        return gl.utils.refreshCurrentPage();
       });
       $('li.group_member').bind('ajax:success', function() {
-        return Turbolinks.visit(location.href);
+        return gl.utils.refreshCurrentPage();
       });
       showBlacklistType = function() {
         if ($("input[name='blacklist_type']:checked").val() === 'file') {
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 4849aab50f4..ad95c1b9dfb 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -24,9 +24,7 @@
 /*= require jquery.waitforimages */
 /*= require jquery.atwho */
 /*= require jquery.scrollTo */
-/*= require jquery.turbolinks */
 /*= require js.cookie */
-/*= require turbolinks */
 /*= require autosave */
 /*= require bootstrap/affix */
 /*= require bootstrap/alert */
@@ -64,7 +62,7 @@
 /*= require es6-promise.auto */
 
 (function () {
-  document.addEventListener('page:fetch', function () {
+  document.addEventListener('beforeunload', function () {
     // Unbind scroll events
     $(document).off('scroll');
     // Close any open tooltips
diff --git a/app/assets/javascripts/breakpoints.js b/app/assets/javascripts/breakpoints.js
index eae062a3aa3..f8dac1ff56e 100644
--- a/app/assets/javascripts/breakpoints.js
+++ b/app/assets/javascripts/breakpoints.js
@@ -43,6 +43,7 @@
       BreakpointInstance.prototype.getBreakpointSize = function() {
         var $visibleDevice;
         $visibleDevice = this.visibleDevice;
+        // TODO: Consider refactoring in light of turbolinks removal.
         // the page refreshed via turbolinks
         if (!$visibleDevice().length) {
           this.setup();
diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js
index 0df84234520..0152be88b48 100644
--- a/app/assets/javascripts/build.js
+++ b/app/assets/javascripts/build.js
@@ -1,6 +1,5 @@
 /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top */
 /* global Breakpoints */
-/* global Turbolinks */
 
 (function() {
   var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
@@ -127,7 +126,7 @@
                 pageUrl += DOWN_BUILD_TRACE;
               }
 
-              return Turbolinks.visit(pageUrl);
+              return gl.utils.visitUrl(pageUrl);
             }
           };
         })(this)
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
index 00e1c28692f..547989a6ff5 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
@@ -9,7 +9,7 @@
       this.setupMapping();
 
       this.cleanupWrapper = this.cleanup.bind(this);
-      document.addEventListener('page:fetch', this.cleanupWrapper);
+      document.addEventListener('beforeunload', this.cleanupWrapper);
     }
 
     cleanup() {
@@ -20,7 +20,7 @@
 
       this.setupMapping();
 
-      document.removeEventListener('page:fetch', this.cleanupWrapper);
+      document.removeEventListener('beforeunload', this.cleanupWrapper);
     }
 
     setupMapping() {
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
index 029564ffc61..4e02ab7c8c1 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
@@ -1,5 +1,3 @@
-/* global Turbolinks */
-
 (() => {
   class FilteredSearchManager {
     constructor() {
@@ -15,13 +13,13 @@
         this.dropdownManager.setDropdown();
 
         this.cleanupWrapper = this.cleanup.bind(this);
-        document.addEventListener('page:fetch', this.cleanupWrapper);
+        document.addEventListener('beforeunload', this.cleanupWrapper);
       }
     }
 
     cleanup() {
       this.unbindEvents();
-      document.removeEventListener('page:fetch', this.cleanupWrapper);
+      document.removeEventListener('beforeunload', this.cleanupWrapper);
     }
 
     bindEvents() {
@@ -200,7 +198,9 @@
         paths.push(`search=${sanitized}`);
       }
 
-      Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`);
+      const parameterizedUrl = `?scope=all&utf8=✓&${paths.join('&')}`;
+
+      gl.utils.visitUrl(parameterizedUrl);
     }
 
     getUsernameParams() {
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index d2f66cf5249..dbc9b2e2a1c 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -1,6 +1,5 @@
 /* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, prefer-rest-params, max-len, vars-on-top, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func, no-mixed-operators */
 /* global fuzzaldrinPlus */
-/* global Turbolinks */
 
 (function() {
   var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote,
@@ -723,7 +722,7 @@
       if ($el.length) {
         var href = $el.attr('href');
         if (href && href !== '#') {
-          Turbolinks.visit(href);
+          gl.utils.visitUrl(href);
         } else {
           $el.first().trigger('click');
         }
diff --git a/app/assets/javascripts/issuable.js.es6 b/app/assets/javascripts/issuable.js.es6
index f63d700fd65..8df86f68218 100644
--- a/app/assets/javascripts/issuable.js.es6
+++ b/app/assets/javascripts/issuable.js.es6
@@ -1,6 +1,5 @@
 /* eslint-disable no-param-reassign, func-names, no-var, camelcase, no-unused-vars, object-shorthand, space-before-function-paren, no-return-assign, comma-dangle, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, prefer-arrow-callback, wrap-iife, max-len */
 /* global Issuable */
-/* global Turbolinks */
 
 ((global) => {
   var issuable_created;
@@ -119,7 +118,7 @@
         issuesUrl = formAction;
         issuesUrl += "" + (formAction.indexOf('?') < 0 ? '?' : '&');
         issuesUrl += formData;
-        return Turbolinks.visit(issuesUrl);
+        return gl.utils.visitUrl(issuesUrl);
       };
     })(this),
     initResetFilters: function() {
@@ -130,7 +129,7 @@
         const baseIssuesUrl = target.href;
 
         $form.attr('action', baseIssuesUrl);
-        Turbolinks.visit(baseIssuesUrl);
+        gl.utils.visitUrl(baseIssuesUrl);
       });
     },
     initChecks: function() {
diff --git a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6
index e810ee85bd3..2955bda1a36 100644
--- a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6
+++ b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6
@@ -95,7 +95,6 @@
       const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;
 
       history.replaceState({
-        turbolinks: true,
         url: newState,
       }, document.title, newState);
       return newState;
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js.es6
similarity index 94%
rename from app/assets/javascripts/lib/utils/url_utility.js
rename to app/assets/javascripts/lib/utils/url_utility.js.es6
index 8e15bf0735c..a1558b371f0 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js.es6
@@ -76,5 +76,11 @@
       hashIndex = url.indexOf('#');
       return hashIndex === -1 ? null : url.substring(hashIndex + 1);
     };
+
+    w.gl.utils.refreshCurrentPage = () => gl.utils.visitUrl(document.location.href);
+
+    w.gl.utils.visitUrl = (url) => {
+      document.location.href = url;
+    };
   })(window);
 }).call(this);
diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js
index 2f147704c22..78e338033e3 100644
--- a/app/assets/javascripts/line_highlighter.js
+++ b/app/assets/javascripts/line_highlighter.js
@@ -171,7 +171,6 @@
     // This method is stubbed in tests.
     LineHighlighter.prototype.__setLocationHash__ = function(value) {
       return history.pushState({
-        turbolinks: false,
         url: value
       // We're using pushState instead of assigning location.hash directly to
       // prevent the page from scrolling on the hashchange event
diff --git a/app/assets/javascripts/logo.js b/app/assets/javascripts/logo.js
index ea9bfb4860a..1b0d0768db8 100644
--- a/app/assets/javascripts/logo.js
+++ b/app/assets/javascripts/logo.js
@@ -1,14 +1,7 @@
 /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback */
-/* global Turbolinks */
 
 (function() {
-  Turbolinks.enableProgressBar();
-
-  $(document).on('page:fetch', function() {
+  window.addEventListener('beforeunload', function() {
     $('.tanuki-logo').addClass('animate');
   });
-
-  $(document).on('page:change', function() {
-    $('.tanuki-logo').removeClass('animate');
-  });
 }).call(this);
diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6
index 4c8c28af755..33463b46008 100644
--- a/app/assets/javascripts/merge_request_tabs.js.es6
+++ b/app/assets/javascripts/merge_request_tabs.js.es6
@@ -184,12 +184,13 @@
       // Ensure parameters and hash come along for the ride
       newState += location.search + location.hash;
 
+      // TODO: Consider refactoring in light of turbolinks removal.
+
       // Replace the current history state with the new one without breaking
       // Turbolinks' history.
       //
       // See https://github.com/rails/turbolinks/issues/363
       window.history.replaceState({
-        turbolinks: true,
         url: newState,
       }, document.title, newState);
 
diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js.es6
index fa782ebbedf..2c19029d175 100644
--- a/app/assets/javascripts/merge_request_widget.js.es6
+++ b/app/assets/javascripts/merge_request_widget.js.es6
@@ -2,7 +2,6 @@
 /* global notify */
 /* global notifyPermissions */
 /* global merge_request_widget */
-/* global Turbolinks */
 
 ((global) => {
   var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; };
@@ -69,13 +68,13 @@
     }
 
     MergeRequestWidget.prototype.clearEventListeners = function() {
-      return $(document).off('page:change.merge_request');
+      return $(document).off('DOMContentLoaded');
     };
 
     MergeRequestWidget.prototype.addEventListeners = function() {
       var allowedPages;
       allowedPages = ['show', 'commits', 'pipelines', 'changes'];
-      $(document).on('page:change.merge_request', (function(_this) {
+      $(document).on('DOMContentLoaded', (function(_this) {
         return function() {
           var page;
           page = $('body').data('page').split(':').last();
diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js
index 7cf630a1d76..399b331c941 100644
--- a/app/assets/javascripts/project.js
+++ b/app/assets/javascripts/project.js
@@ -1,6 +1,5 @@
 /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */
 /* global Cookies */
-/* global Turbolinks */
 /* global ProjectSelect */
 
 (function() {
@@ -99,7 +98,7 @@
               var $form = $dropdown.closest('form');
               var action = $form.attr('action');
               var divider = action.indexOf('?') < 0 ? '?' : '&';
-              Turbolinks.visit(action + '' + divider + '' + $form.serialize());
+              gl.utils.visitUrl(action + '' + divider + '' + $form.serialize());
             }
           }
         });
diff --git a/app/assets/javascripts/project_import.js b/app/assets/javascripts/project_import.js
index 6614d8952cd..d7943959238 100644
--- a/app/assets/javascripts/project_import.js
+++ b/app/assets/javascripts/project_import.js
@@ -1,11 +1,10 @@
 /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */
-/* global Turbolinks */
 
 (function() {
   this.ProjectImport = (function() {
     function ProjectImport() {
       setTimeout(function() {
-        return Turbolinks.visit(location.href);
+        return gl.utils.visitUrl(location.href);
       }, 5000);
     }
 
diff --git a/app/assets/javascripts/render_gfm.js b/app/assets/javascripts/render_gfm.js
index 0caf8ba4344..bdbad93ad04 100644
--- a/app/assets/javascripts/render_gfm.js
+++ b/app/assets/javascripts/render_gfm.js
@@ -9,7 +9,7 @@
     this.find('.js-render-math').renderMath();
   };
 
-  $(document).on('ready page:load', function() {
+  $(document).on('ready load', function() {
     return $('body').renderGFM();
   });
 }).call(this);
diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/shortcuts.js
index c56ee429b8e..c6d9b007ad1 100644
--- a/app/assets/javascripts/shortcuts.js
+++ b/app/assets/javascripts/shortcuts.js
@@ -1,6 +1,5 @@
 /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
 /* global Mousetrap */
-/* global Turbolinks */
 /* global findFileURL */
 
 (function() {
@@ -23,7 +22,7 @@
       Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], this.toggleMarkdownPreview);
       if (typeof findFileURL !== "undefined" && findFileURL !== null) {
         Mousetrap.bind('t', function() {
-          return Turbolinks.visit(findFileURL);
+          return gl.utils.visitUrl(findFileURL);
         });
       }
     }
diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js
index 4dcc5ebe28f..3501974a8c9 100644
--- a/app/assets/javascripts/shortcuts_issuable.js
+++ b/app/assets/javascripts/shortcuts_issuable.js
@@ -1,6 +1,5 @@
 /* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, one-var-declaration-per-line, quotes, prefer-arrow-callback, consistent-return, prefer-template, no-mixed-operators */
 /* global Mousetrap */
-/* global Turbolinks */
 /* global ShortcutsNavigation */
 /* global sidebar */
 
@@ -80,7 +79,7 @@
     ShortcutsIssuable.prototype.editIssue = function() {
       var $editBtn;
       $editBtn = $('.issuable-edit');
-      return Turbolinks.visit($editBtn.attr('href'));
+      return gl.utils.visitUrl($editBtn.attr('href'));
     };
 
     ShortcutsIssuable.prototype.openSidebarDropdown = function(name) {
diff --git a/app/assets/javascripts/sidebar.js.es6 b/app/assets/javascripts/sidebar.js.es6
index 05234643c18..ee172f2fa6f 100644
--- a/app/assets/javascripts/sidebar.js.es6
+++ b/app/assets/javascripts/sidebar.js.es6
@@ -40,7 +40,7 @@
         .on('click', sidebarToggleSelector, () => this.toggleSidebar())
         .on('click', pinnedToggleSelector, () => this.togglePinnedState())
         .on('click', 'html, body', (e) => this.handleClickEvent(e))
-        .on('page:change', () => this.renderState())
+        .on('DOMContentLoaded', () => this.renderState())
         .on('todo:toggle', (e, count) => this.updateTodoCount(count));
       this.renderState();
     }
diff --git a/app/assets/javascripts/smart_interval.js.es6 b/app/assets/javascripts/smart_interval.js.es6
index 40f67637c7c..d1bdc353be2 100644
--- a/app/assets/javascripts/smart_interval.js.es6
+++ b/app/assets/javascripts/smart_interval.js.es6
@@ -89,7 +89,7 @@
     destroy() {
       this.cancel();
       document.removeEventListener('visibilitychange', this.handleVisibilityChange);
-      $(document).off('visibilitychange').off('page:before-unload');
+      $(document).off('visibilitychange').off('beforeunload');
     }
 
     /* private */
@@ -111,8 +111,9 @@
     }
 
     initPageUnloadHandling() {
+      // TODO: Consider refactoring in light of turbolinks removal.
       // prevent interval continuing after page change, when kept in cache by Turbolinks
-      $(document).on('page:before-unload', () => this.cancel());
+      $(document).on('beforeunload', () => this.cancel());
     }
 
     handleVisibilityChange(e) {
diff --git a/app/assets/javascripts/todos.js.es6 b/app/assets/javascripts/todos.js.es6
index 05622916ff8..96c7d927509 100644
--- a/app/assets/javascripts/todos.js.es6
+++ b/app/assets/javascripts/todos.js.es6
@@ -1,6 +1,5 @@
 /* eslint-disable class-methods-use-this, no-new, func-names, prefer-template, no-unneeded-ternary, object-shorthand, space-before-function-paren, comma-dangle, quote-props, consistent-return, no-else-return, no-param-reassign, max-len */
 /* global UsersSelect */
-/* global Turbolinks */
 
 ((global) => {
   class Todos {
@@ -34,7 +33,7 @@
 
       $('form.filter-form').on('submit', function (event) {
         event.preventDefault();
-        Turbolinks.visit(this.action + '&' + $(this).serialize());
+        gl.utils.visitUrl(this.action + '&' + $(this).serialize());
       });
     }
 
@@ -142,7 +141,7 @@
           };
           url = gl.utils.mergeUrlParams(pageParams, url);
         }
-        return Turbolinks.visit(url);
+        return gl.utils.visitUrl(url);
       }
     }
 
@@ -156,7 +155,7 @@
         e.preventDefault();
         return window.open(todoLink, '_blank');
       } else {
-        return Turbolinks.visit(todoLink);
+        return gl.utils.visitUrl(todoLink);
       }
     }
   }
diff --git a/app/assets/javascripts/tree.js b/app/assets/javascripts/tree.js
index d124ca4f88b..b1b35fdbd6c 100644
--- a/app/assets/javascripts/tree.js
+++ b/app/assets/javascripts/tree.js
@@ -1,5 +1,5 @@
 /* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, max-len */
-/* global Turbolinks */
+
 (function() {
   this.TreeView = (function() {
     function TreeView() {
@@ -15,7 +15,7 @@
             e.preventDefault();
             return window.open(path, '_blank');
           } else {
-            return Turbolinks.visit(path);
+            return gl.utils.visitUrl(path);
           }
         }
       });
@@ -57,7 +57,7 @@
         } else if (e.which === 13) {
           path = $('.tree-item.selected .tree-item-file-name a').attr('href');
           if (path) {
-            return Turbolinks.visit(path);
+            return gl.utils.visitUrl(path);
           }
         }
       });
diff --git a/app/assets/javascripts/user_tabs.js.es6 b/app/assets/javascripts/user_tabs.js.es6
index 313fb17aee8..465618e3d53 100644
--- a/app/assets/javascripts/user_tabs.js.es6
+++ b/app/assets/javascripts/user_tabs.js.es6
@@ -149,7 +149,6 @@ content on the Users#show page.
       new_state = new_state.replace(/\/+$/, '');
       new_state += this._location.search + this._location.hash;
       history.replaceState({
-        turbolinks: true,
         url: new_state
       }, document.title, new_state);
       return new_state;
diff --git a/app/assets/javascripts/vue_pagination/index.js.es6 b/app/assets/javascripts/vue_pagination/index.js.es6
index 605824fa939..d94caa983cd 100644
--- a/app/assets/javascripts/vue_pagination/index.js.es6
+++ b/app/assets/javascripts/vue_pagination/index.js.es6
@@ -13,6 +13,8 @@
   gl.VueGlPagination = Vue.extend({
     props: {
 
+      // TODO: Consider refactoring in light of turbolinks removal.
+
       /**
         This function will take the information given by the pagination component
         And make a new Turbolinks call
@@ -20,7 +22,7 @@
         Here is an example `change` method:
 
         change(pagenum, apiScope) {
-          Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`);
+          gl.utils.visitUrl(`?scope=${apiScope}&p=${pagenum}`);
         },
       */
 
diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6
index b2ed05503c9..194bbae07d9 100644
--- a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6
+++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6
@@ -1,4 +1,4 @@
-/* global Vue, Turbolinks, gl */
+/* global Vue, gl */
 /* eslint-disable no-param-reassign */
 
 ((gl) => {
@@ -36,7 +36,7 @@
     },
     methods: {
       change(pagenum, apiScope) {
-        Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`);
+        gl.utils.visitUrl(`?scope=${apiScope}&p=${pagenum}`);
       },
       author(pipeline) {
         if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' };
diff --git a/app/assets/javascripts/vue_realtime_listener/index.js.es6 b/app/assets/javascripts/vue_realtime_listener/index.js.es6
index 23cac1466d2..95564152cce 100644
--- a/app/assets/javascripts/vue_realtime_listener/index.js.es6
+++ b/app/assets/javascripts/vue_realtime_listener/index.js.es6
@@ -7,12 +7,12 @@
       window.removeEventListener('beforeunload', removeIntervals);
       window.removeEventListener('focus', startIntervals);
       window.removeEventListener('blur', removeIntervals);
-      document.removeEventListener('page:fetch', removeAll);
+      document.removeEventListener('beforeunload', removeAll);
     };
 
     window.addEventListener('beforeunload', removeIntervals);
     window.addEventListener('focus', startIntervals);
     window.addEventListener('blur', removeIntervals);
-    document.addEventListener('page:fetch', removeAll);
+    document.addEventListener('beforeunload', removeAll);
   };
 })(window.gl || (window.gl = {}));
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 3cf49f4ff1b..08f203a1bf6 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -31,7 +31,6 @@
 @import "framework/modal.scss";
 @import "framework/nav.scss";
 @import "framework/pagination.scss";
-@import "framework/progress.scss";
 @import "framework/panels.scss";
 @import "framework/selects.scss";
 @import "framework/sidebar.scss";
diff --git a/app/assets/stylesheets/framework/progress.scss b/app/assets/stylesheets/framework/progress.scss
deleted file mode 100644
index e9800bd24b5..00000000000
--- a/app/assets/stylesheets/framework/progress.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-html.turbolinks-progress-bar::before {
-  background-color: $progress-color!important;
-  height: 2px!important;
-  box-shadow: 0 0 10px $progress-color, 0 0 5px $progress-color;
-}
diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb
index 0e456214d37..cd4075b340d 100644
--- a/app/helpers/javascript_helper.rb
+++ b/app/helpers/javascript_helper.rb
@@ -1,5 +1,5 @@
 module JavascriptHelper
   def page_specific_javascript_tag(js)
-    javascript_include_tag asset_path(js), { "data-turbolinks-track" => true }
+    javascript_include_tag asset_path(js)
   end
 end
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index e87a16a5157..f92f89e73ff 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -6,4 +6,4 @@
     - providers.each do |provider|
       %span.light
         - has_icon = provider_has_icon?(provider)
-        = link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true"
+        = link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn')
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index 7f1b9ee7141..e18bd47798b 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -82,7 +82,7 @@
     rather than Git. Please convert
     = link_to 'them to Git,', 'https://www.atlassian.com/git/tutorials/migrating-overview'
     and go through the
-    = link_to 'import flow', status_import_bitbucket_path, 'data-no-turbolink' => 'true'
+    = link_to 'import flow', status_import_bitbucket_path
     again.
 
 .js-importer-status{ data: { jobs_import_path: "#{jobs_import_bitbucket_path}", import_path: "#{import_bitbucket_path}" } }
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 3096f0ee19e..703c1009d5f 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -33,6 +33,8 @@
   - if content_for?(:page_specific_javascripts)
     = yield :page_specific_javascripts
 
+  = yield :scripts_body_top
+
   = csrf_meta_tags
 
   - unless browser.safari?
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 935517d4913..248d439cd05 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -4,9 +4,6 @@
   %body{ class: "#{user_application_theme}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } }
     = Gon::Base.render_data
 
-    -# Ideally this would be inside the head, but turbolinks only evaluates page-specific JS in the body.
-    = yield :scripts_body_top
-
     = render "layouts/header/default", title: header_title
     = render 'layouts/page', sidebar: sidebar, nav: nav
 
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 14b330d16ad..a4f4079d556 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -82,7 +82,7 @@
               = link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'provider-btn' do
                 Disconnect
           - else
-            = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn not-active', "data-no-turbolink" => "true" do
+            = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn not-active' do
               Connect
   %hr
 - if current_user.can_change_username?
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 9585a9a3ad4..b38bd32745b 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -108,10 +108,10 @@
   = render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit, title: @merge_request.title
 
 :javascript
-  var merge_request;
-
-  merge_request = new MergeRequest({
-    action: "#{controller.action_name}"
+  $(function () {
+    new MergeRequest({
+      action: "#{controller.action_name}"
+    });
   });
 
   var mrRefreshWidgetUrl = "#{mr_widget_refresh_url(@merge_request)}";
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 064e92b15eb..cd685f7d0eb 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -50,7 +50,7 @@
                       = icon('github', text: 'GitHub')
                 %div
                   - if bitbucket_import_enabled?
-                    = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}", "data-no-turbolink" => "true" do
+                    = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}" do
                       = icon('bitbucket', text: 'Bitbucket')
                     - unless bitbucket_import_configured?
                       = render 'bitbucket_import_modal'
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index b42eaabb111..55777f21040 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -91,5 +91,5 @@
   new SubscriptionSelect();
   $('form.filter-form').on('submit', function (event) {
     event.preventDefault();
-    Turbolinks.visit(this.action + '&' + $(this).serialize());
+    gl.utils.visitUrl(this.action + '&' + $(this).serialize());
   });
diff --git a/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml b/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml
new file mode 100644
index 00000000000..d7f950d7be9
--- /dev/null
+++ b/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml
@@ -0,0 +1,4 @@
+---
+title: Remove turbolinks.
+merge_request: !8570
+author:
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index d2fa8cd39af..480906929b2 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -501,6 +501,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
 
   step 'I fill in merge request search with "Fe"' do
     fill_in 'issuable_search', with: "Fe"
+    sleep 3
   end
 
   step 'I click the "Target branch" dropdown' do
diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js
index 51d911792ba..5f2c73634a8 100644
--- a/spec/javascripts/behaviors/autosize_spec.js
+++ b/spec/javascripts/behaviors/autosize_spec.js
@@ -15,7 +15,7 @@
       });
     });
     return load = function() {
-      return $(document).trigger('page:load');
+      return $(document).trigger('load');
     };
   });
 }).call(this);
diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js
index 9467056f04c..b1b1f1f437b 100644
--- a/spec/javascripts/behaviors/requires_input_spec.js
+++ b/spec/javascripts/behaviors/requires_input_spec.js
@@ -34,11 +34,5 @@
       $('#required5').val('1').change();
       return expect($('.submit')).not.toBeDisabled();
     });
-    return it('is called on page:load event', function() {
-      var spy;
-      spy = spyOn($.fn, 'requiresInput');
-      $(document).trigger('page:load');
-      return expect(spy).toHaveBeenCalled();
-    });
   });
 }).call(this);
diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6
index ea953d0f5a5..cac77cf67a0 100644
--- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6
+++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6
@@ -50,7 +50,6 @@
         secondTab.click();
 
         expect(historySpy).toHaveBeenCalledWith({
-          turbolinks: true,
           url: newState,
         }, document.title, newState);
       });
diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6
index 0c556382980..d813d6b39d0 100644
--- a/spec/javascripts/build_spec.js.es6
+++ b/spec/javascripts/build_spec.js.es6
@@ -1,12 +1,11 @@
 /* eslint-disable no-new */
 /* global Build */
-/* global Turbolinks */
 
 //= require lib/utils/datetime_utility
+//= require lib/utils/url_utility
 //= require build
 //= require breakpoints
 //= require jquery.nicescroll
-//= require turbolinks
 
 describe('Build', () => {
   const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1`;
@@ -167,7 +166,7 @@ describe('Build', () => {
       });
 
       it('reloads the page when the build is done', () => {
-        spyOn(Turbolinks, 'visit');
+        spyOn(gl.utils, 'visitUrl');
 
         jasmine.clock().tick(4001);
         const [{ success, context }] = $.ajax.calls.argsFor(1);
@@ -177,7 +176,7 @@ describe('Build', () => {
           append: true,
         });
 
-        expect(Turbolinks.visit).toHaveBeenCalledWith(BUILD_URL);
+        expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL);
       });
     });
   });
diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6
index 06fa64b1b4e..b8d39019183 100644
--- a/spec/javascripts/gl_dropdown_spec.js.es6
+++ b/spec/javascripts/gl_dropdown_spec.js.es6
@@ -1,11 +1,10 @@
 /* eslint-disable comma-dangle, no-param-reassign, no-unused-expressions, max-len */
-/* global Turbolinks */
 
 /*= require jquery */
 /*= require gl_dropdown */
-/*= require turbolinks */
 /*= require lib/utils/common_utils */
 /*= require lib/utils/type_utility */
+//= require lib/utils/url_utility
 
 (() => {
   const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
@@ -112,13 +111,13 @@
         expect(this.dropdownContainerElement).toHaveClass('open');
         const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0;
         navigateWithKeys('down', randomIndex, () => {
-          spyOn(Turbolinks, 'visit').and.stub();
+          spyOn(gl.utils, 'visitUrl').and.stub();
           navigateWithKeys('enter', null, () => {
             expect(this.dropdownContainerElement).not.toHaveClass('open');
             const link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement);
             expect(link).toHaveClass('is-active');
             const linkedLocation = link.attr('href');
-            if (linkedLocation && linkedLocation !== '#') expect(Turbolinks.visit).toHaveBeenCalledWith(linkedLocation);
+            if (linkedLocation && linkedLocation !== '#') expect(gl.utils.visitUrl).toHaveBeenCalledWith(linkedLocation);
           });
         });
       });
diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6
index 917a6267b92..9bea404379b 100644
--- a/spec/javascripts/issuable_spec.js.es6
+++ b/spec/javascripts/issuable_spec.js.es6
@@ -1,8 +1,7 @@
 /* global Issuable */
-/* global Turbolinks */
 
+//= require lib/utils/url_utility
 //= require issuable
-//= require turbolinks
 
 (() => {
   const BASE_URL = '/user/project/issues?scope=all&state=closed';
@@ -42,39 +41,39 @@
       });
 
       it('should contain only the default parameters', () => {
-        spyOn(Turbolinks, 'visit');
+        spyOn(gl.utils, 'visitUrl');
 
         Issuable.filterResults($filtersForm);
 
-        expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + DEFAULT_PARAMS);
+        expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + DEFAULT_PARAMS);
       });
 
       it('should filter for the phrase "broken"', () => {
-        spyOn(Turbolinks, 'visit');
+        spyOn(gl.utils, 'visitUrl');
 
         updateForm({ search: 'broken' }, $filtersForm);
         Issuable.filterResults($filtersForm);
         const params = `${DEFAULT_PARAMS}&search=broken`;
 
-        expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params);
+        expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params);
       });
 
       it('should keep query parameters after modifying filter', () => {
-        spyOn(Turbolinks, 'visit');
+        spyOn(gl.utils, 'visitUrl');
 
         // initial filter
         updateForm({ milestone_title: 'v1.0' }, $filtersForm);
 
         Issuable.filterResults($filtersForm);
         let params = `${DEFAULT_PARAMS}&milestone_title=v1.0`;
-        expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params);
+        expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params);
 
         // update filter
         updateForm({ label_name: 'Frontend' }, $filtersForm);
 
         Issuable.filterResults($filtersForm);
         params = `${DEFAULT_PARAMS}&milestone_title=v1.0&label_name=Frontend`;
-        expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params);
+        expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params);
       });
     });
   });
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index 98201fb98ed..6009f0dbfc2 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -99,7 +99,6 @@
         });
         newState = this.subject('commits');
         expect(this.spies.history).toHaveBeenCalledWith({
-          turbolinks: true,
           url: newState
         }, document.title, newState);
       });
diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js
index 7ac9710654f..0b48a53f4bc 100644
--- a/spec/javascripts/search_autocomplete_spec.js
+++ b/spec/javascripts/search_autocomplete_spec.js
@@ -6,8 +6,6 @@
 /*= require lib/utils/common_utils */
 /*= require lib/utils/type_utility */
 /*= require fuzzaldrin-plus */
-/*= require turbolinks */
-/*= require jquery.turbolinks */
 
 (function() {
   var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget;
diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6
index 39d236986b9..e695454b8f7 100644
--- a/spec/javascripts/smart_interval_spec.js.es6
+++ b/spec/javascripts/smart_interval_spec.js.es6
@@ -164,7 +164,7 @@
         const interval = this.smartInterval;
 
         setTimeout(() => {
-          $(document).trigger('page:before-unload');
+          $(document).trigger('beforeunload');
           expect(interval.state.intervalId).toBeUndefined();
           expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval);
           done();
diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js
index f8e3aca29fa..a89176e9ef4 100644
--- a/spec/javascripts/spec_helper.js
+++ b/spec/javascripts/spec_helper.js
@@ -8,7 +8,6 @@
 // everything in application, however you may get better load performance if you
 // require the specific files that are being used in the spec that tests them.
 /*= require jquery */
-/*= require jquery.turbolinks */
 /*= require bootstrap */
 /*= require underscore */
 
diff --git a/vendor/assets/javascripts/jquery.turbolinks.js b/vendor/assets/javascripts/jquery.turbolinks.js
deleted file mode 100644
index fd6e95e75d5..00000000000
--- a/vendor/assets/javascripts/jquery.turbolinks.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// Generated by CoffeeScript 1.7.1
-
-/*
-jQuery.Turbolinks ~ https://github.com/kossnocorp/jquery.turbolinks
-jQuery plugin for drop-in fix binded events problem caused by Turbolinks
-
-The MIT License
-Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz
- */
-
-(function() {
-  var $, $document;
-
-  $ = window.jQuery || (typeof require === "function" ? require('jquery') : void 0);
-
-  $document = $(document);
-
-  $.turbo = {
-    version: '2.1.0',
-    isReady: false,
-    use: function(load, fetch) {
-      return $document.off('.turbo').on("" + load + ".turbo", this.onLoad).on("" + fetch + ".turbo", this.onFetch);
-    },
-    addCallback: function(callback) {
-      if ($.turbo.isReady) {
-        callback($);
-      }
-      return $document.on('turbo:ready', function() {
-        return callback($);
-      });
-    },
-    onLoad: function() {
-      $.turbo.isReady = true;
-      return $document.trigger('turbo:ready');
-    },
-    onFetch: function() {
-      return $.turbo.isReady = false;
-    },
-    register: function() {
-      $(this.onLoad);
-      return $.fn.ready = this.addCallback;
-    }
-  };
-
-  $.turbo.register();
-
-  $.turbo.use('page:load', 'page:fetch');
-
-}).call(this);
-- 
GitLab