From da658f3d8c3ed6f324f253c4c4fe6bdfd99a300a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 2 Jul 2020 12:24:32 +0200 Subject: [PATCH] Hack datepicker to make it work with Turbolinks 5.x Patch extracted from here the comments on turbolinks issue 253 and converted to vanilla javascript. The hide action over datepickers ensures us that opened datepickers will be closed before leving the page. Previously if you open any datepicker and then move to previous page you will keep seeing the datepicker in the restored page. --- app/assets/javascripts/application.js | 2 ++ app/assets/javascripts/datepicker.js | 31 +++++++++++++++++++++++++++ spec/system/admin/banners_spec.rb | 28 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 app/assets/javascripts/datepicker.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 776f9931e..512d89bfd 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -111,6 +111,7 @@ //= require cookies //= require columns_selector //= require budget_edit_associations +//= require datepicker var initialize_modules = function() { "use strict"; @@ -169,6 +170,7 @@ var initialize_modules = function() { var destroy_non_idempotent_modules = function() { "use strict"; + App.Datepicker.destroy(); App.HTMLEditor.destroy(); }; diff --git a/app/assets/javascripts/datepicker.js b/app/assets/javascripts/datepicker.js new file mode 100644 index 000000000..b44fa8e58 --- /dev/null +++ b/app/assets/javascripts/datepicker.js @@ -0,0 +1,31 @@ +// Based on code by Javan Makhmali +// https://github.com/turbolinks/turbolinks/issues/253#issuecomment-289101048 +// The jQuery UI date picker widget appends a shared element to the +// body which it expects will never leave the page, but Turbolinks +// removes that shared element when it rerenders. We satisfy that +// expectation by removing the shared element from the page before +// Turbolinks caches the page, and appending it again before +// Turbolinks swaps the new body in during rendering. +// +// Additionally, returning to the cached version of a page that +// previously had date picker elements would result in those date +// pickers not being initialized again. We fix this issue by finding +// all initialized date picker inputs on the page and calling the +// date picker's destroy method before Turbolinks caches the page. +(function() { + "use strict"; + App.Datepicker = { + destroy: function() { + $.datepicker.dpDiv.remove(); + + document.querySelectorAll("input.hasDatepicker").forEach(function(input) { + $(input).datepicker("hide"); + $(input).datepicker("destroy"); + }); + } + }; + + document.addEventListener("turbolinks:before-render", function(event) { + $.datepicker.dpDiv.appendTo(event.data.newBody); + }); +}).call(this); diff --git a/spec/system/admin/banners_spec.rb b/spec/system/admin/banners_spec.rb index 3b30f792b..9cd5e643c 100644 --- a/spec/system/admin/banners_spec.rb +++ b/spec/system/admin/banners_spec.rb @@ -190,6 +190,34 @@ describe "Admin banners magement" do expect(page).to have_field "Post started at", with: "22/02/2002" end + scenario "when date picker is opened and click on browser history back datepicker is closed", :js do + banner = create(:banner) + visit admin_banners_path(banner) + click_link "Edit banner" + find_field("Post started at").click + + expect(page).to have_css "#ui-datepicker-div" + + go_back + + expect(page).to have_content("Banners") + expect(page).not_to have_css "#ui-datepicker-div" + end + + scenario "date picker works after using the browser back button", :js do + banner = create(:banner) + + visit edit_admin_banner_path(banner) + click_link "Manage banners" + + expect(page).to have_link "Edit banner" + + go_back + find_field("Post started at").click + + expect(page).to have_css "#ui-datepicker-div" + end + scenario "Delete a banner" do create(:banner, title: "Ugly banner", description: "Bad text",