Skip to content

Commit 5f3db51

Browse files
authored
Merge pull request #378 from matestack/232
#232: added turbolinks handler
2 parents 2520e26 + 63e18ec commit 5f3db51

File tree

16 files changed

+340
-36
lines changed

16 files changed

+340
-36
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ group :development, :test do
2929
gem 'webmock'
3030
gem 'pry-rails'
3131
gem 'pry-byebug'
32+
gem 'turbolinks'
3233
end
3334

3435
group :test do

Gemfile.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ GEM
237237
reform-rails (>= 0.1.4, < 0.2.0)
238238
trailblazer (~> 2.0.0)
239239
trailblazer-loader (>= 0.1.0)
240+
turbolinks (5.2.1)
241+
turbolinks-source (~> 5.2)
242+
turbolinks-source (5.2.0)
240243
tzinfo (1.2.6)
241244
thread_safe (~> 0.1)
242245
uber (0.1.0)
@@ -276,6 +279,7 @@ DEPENDENCIES
276279
trailblazer
277280
trailblazer-cells
278281
trailblazer-rails
282+
turbolinks
279283
webmock
280284
webpacker (~> 4.0)
281285

app/concepts/matestack/ui/core/app/store.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ const store = new Vuex.Store({
2020
state.currentPathName = current.path
2121
state.currentSearch = current.search
2222
state.currentOrigin = current.origin
23+
},
24+
resetPageTemplate (state) {
25+
state.pageTemplate = null;
2326
}
2427
},
2528
actions: {

app/concepts/matestack/ui/core/js/core.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Vue from 'vue/dist/vue.esm'
2+
import { turbolinksAdapterMixin } from 'vue-turbolinks';
23

34
// Import from app/concepts/matestack/ui/core:
45
import app from '../app/app'
@@ -18,13 +19,35 @@ import collectionOrder from '../collection/order/order'
1819

1920
let matestackUiApp = undefined
2021

22+
// this event fires first and always
2123
document.addEventListener('DOMContentLoaded', () => {
22-
23-
matestackUiApp = new Vue({
24+
// somehow we need to inject the turbolinks mixin even
25+
// if the turbolinks:load event will recreate the vue instance
26+
// skipping the injection here caused errors when submitting forms or action
27+
// if they were present on the first page, which was loaded and activated turbolinks
28+
// the mixin does not impact the app when turbolinks is disabled
29+
matestackUiApp = new Vue({
2430
el: "#matestack_ui",
31+
mixins: [turbolinksAdapterMixin],
2532
store: store
26-
})
33+
})
34+
})
2735

36+
// this event fires after DOMContentLoaded and only if turbolinks are enabled
37+
document.addEventListener('turbolinks:load', () => {
38+
// we need to empty the currently stored pageTemplate state variable
39+
// otherwise the matestack page will jump back to the latest pageTemplate
40+
// fetched during the last matestack transition as the turbolinks powered
41+
// page transition does not write the matestack store pageTemplate state variable
42+
store.commit('resetPageTemplate')
43+
// we need to destroy the vue app instance
44+
matestackUiApp.$destroy();
45+
// and recreate it right afterwards in order to work when used with turbolinks
46+
matestackUiApp = new Vue({
47+
el: "#matestack_ui",
48+
mixins: [turbolinksAdapterMixin],
49+
store: store
50+
})
2851
})
2952

3053
export default Vue

docs/install/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ Require 'matestack-ui-core' in your `app/assets/stylesheets/application.css`
6565
*/
6666
```
6767

68-
### Turbolinks Coming Soon
68+
### Turbolinks
6969

70-
At the moment, matestack-ui-core is not compatible with [turbolinks](https://github.com/turbolinks/turbolinks). Please remove or deactive turbolinks for now. We are working on turbolinks support and will add it soon. ([Issue #232](https://github.com/matestack/matestack-ui-core/issues/232))
70+
Since `0.7.5`, matestack-ui-core is compatible with activated [turbolinks](https://github.com/turbolinks/turbolinks).
71+
72+
We recommend to (remove/deactivate)(https://stackoverflow.com/a/38649595) turbolinks, as there is no real reason to use it alongside matetack-ui-core UI dynamics and there might appear some strange side effects. If you encounter strange page-transition/form-submit/action-submit behavior and have turbolinks activated, try to deactivate it first.
7173

7274
## Matestack Folder
7375

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
"link-module-alias": "^1.2.0",
99
"v-runtime-template": "^1.5.2",
1010
"vue": "^2.5.17",
11+
"vue-turbolinks": "^2.1.0",
1112
"vuex": "^3.0.1",
1213
"yarn": "^1.22.0"
1314
},
1415
"exports": {
1516
"./concepts/": "./app/concepts/matestack/ui/core/"
16-
},
17+
},
1718
"scripts": {
1819
"postinstall": "link-module-alias"
1920
},

spec/dummy/app/assets/javascripts/application.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//= require rails-ujs
1414
//= require activestorage
1515
//= require matestack-ui-core
16-
//= require_tree .
16+
//= require cable
1717

1818
//= require demo/component
1919

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// This is a manifest file that'll be compiled into application.js, which will include all the files
2+
// listed below.
3+
//
4+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6+
//
7+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
9+
//
10+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11+
// about supported directives.
12+
//
13+
//= require rails-ujs
14+
//= require activestorage
15+
//= require turbolinks
16+
//= require matestack-ui-core
17+
//= require cable
18+
19+
//= require demo/component
20+
21+
App.cable.subscriptions.create("MatestackUiCoreChannel", {
22+
received(data) {
23+
MatestackUiCore.matestackEventHub.$emit('MatestackUiCoreChannel', data)
24+
}
25+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Dummy</title>
5+
<%= csrf_meta_tags %>
6+
<%= csp_meta_tag %>
7+
8+
<%= stylesheet_link_tag 'application', media: 'all' %>
9+
<%= javascript_include_tag 'application_with_turbolinks' %>
10+
</head>
11+
12+
<body>
13+
<div id="matestack_ui">
14+
<%= yield %>
15+
</div>
16+
</body>
17+
</html>

spec/dummy/config/initializers/assets.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# Precompile additional assets.
1313
# application.js, application.css, and all non-JS/CSS in the app/assets
1414
# folder are already added.
15-
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
15+
Rails.application.config.assets.precompile += %w( application_with_turbolinks.js )

spec/dummy/yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4371,7 +4371,7 @@ matestack-ui-core@../../:
43714371
v-runtime-template "^1.5.2"
43724372
vue "^2.5.17"
43734373
vuex "^3.0.1"
4374-
yarn "^1.17.3"
4374+
yarn "^1.22.0"
43754375

43764376
md5.js@^1.3.4:
43774377
version "1.3.5"
@@ -7870,7 +7870,7 @@ yargs@^7.0.0:
78707870
y18n "^3.2.1"
78717871
yargs-parser "^5.0.0"
78727872

7873-
yarn@^1.17.3:
7874-
version "1.22.0"
7875-
resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.0.tgz#acf82906e36bcccd1ccab1cfb73b87509667c881"
7876-
integrity sha512-KMHP/Jq53jZKTY9iTUt3dIVl/be6UPs2INo96+BnZHLKxYNTfwMmlgHTaMWyGZoO74RI4AIFvnWhYrXq2USJkg==
7873+
yarn@^1.22.0:
7874+
version "1.22.4"
7875+
resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.4.tgz#01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e"
7876+
integrity sha512-oYM7hi/lIWm9bCoDMEWgffW8aiNZXCWeZ1/tGy0DWrN6vmzjCXIKu2Y21o8DYVBUtiktwKcNoxyGl/2iKLUNGA==

spec/spec_helper.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
require 'pry'
4040

4141
require 'rspec/retry'
42-
require "rspec/wait"
42+
require "rspec/wait"
4343

4444
RSpec.configure do |config|
4545
# repeat flaky tests
@@ -50,14 +50,14 @@
5050

5151
# run retry only on features
5252
config.around :each, :js do |ex|
53-
ex.run_with_retry retry: 10
53+
ex.run_with_retry retry: 3
5454
end
5555

56-
# callback to be run between retries
56+
# callback to be run between retries
5757
config.retry_callback = proc do |ex|
5858
# run some additional clean up task - can be filtered by example metadata
5959
if ex.metadata[:js]
60-
Capybara.reset!
60+
Capybara.reset!
6161
end
6262
end
6363
# config.include Capybara::DSL
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
describe "Turbolinks integration", type: :feature, js: true do
2+
3+
class TestController < ActionController::Base
4+
5+
before_action :check_params
6+
7+
def check_params
8+
expect_params(params.permit!.to_h)
9+
end
10+
11+
def expect_params(params)
12+
end
13+
14+
end
15+
16+
it "Matestack can be used with turbolinks" do
17+
18+
module Apps
19+
end
20+
21+
class Apps::TurbolinksTest < Matestack::Ui::App
22+
def response
23+
components {
24+
nav do
25+
link path: :turbolinks1_path do
26+
button text: "Link to Page 1"
27+
end
28+
transition path: :turbolinks2_path do
29+
button text: "Transition to Page 2"
30+
end
31+
link path: :turbolinks3_path do
32+
button text: "Link to Page 3"
33+
end
34+
end
35+
main do
36+
page_content
37+
end
38+
}
39+
end
40+
end
41+
42+
module Pages::TurbolinksTest
43+
end
44+
45+
class Pages::TurbolinksTest::Page1 < Matestack::Ui::Page
46+
def response
47+
components {
48+
plain "Hello from matestack with turbolinks - Page 1"
49+
}
50+
end
51+
end
52+
class Pages::TurbolinksTest::Page2 < Matestack::Ui::Page
53+
def response
54+
components {
55+
plain "Hello from matestack with turbolinks - Page 2"
56+
}
57+
end
58+
end
59+
class Pages::TurbolinksTest::Page3 < Matestack::Ui::Page
60+
def response
61+
components {
62+
plain "Hello from matestack with turbolinks - Page 3"
63+
action action_config do
64+
button text: "click me"
65+
end
66+
}
67+
end
68+
69+
def action_config
70+
return {
71+
method: :post,
72+
path: :action_test_path,
73+
data: {
74+
foo: "bar"
75+
}
76+
}
77+
end
78+
end
79+
80+
Rails.application.routes.append do
81+
get '/turbolinks1', to: 'turbolinks_test#page1', as: :turbolinks1
82+
get '/turbolinks2', to: 'turbolinks_test#page2', as: :turbolinks2
83+
get '/turbolinks3', to: 'turbolinks_test#page3', as: :turbolinks3
84+
post '/action_test', to: 'action_test#test'
85+
end
86+
Rails.application.reload_routes!
87+
88+
class TurbolinksTestController < ActionController::Base
89+
layout "application_with_turbolinks"
90+
91+
include Matestack::Ui::Core::ApplicationHelper
92+
93+
def page1
94+
responder_for(Pages::TurbolinksTest::Page1)
95+
end
96+
def page2
97+
responder_for(Pages::TurbolinksTest::Page2)
98+
end
99+
def page3
100+
responder_for(Pages::TurbolinksTest::Page3)
101+
end
102+
end
103+
104+
class ActionTestController < TestController
105+
106+
def test
107+
render json: {}, status: 200
108+
end
109+
110+
end
111+
allow_any_instance_of(ActionTestController).to receive(:expect_params)
112+
113+
114+
visit "/turbolinks1"
115+
116+
expect(page).to have_text "Hello from matestack with turbolinks - Page 1"
117+
118+
click_button "Transition to Page 2"
119+
120+
expect(page).to have_text "Hello from matestack with turbolinks - Page 2"
121+
122+
click_button "Link to Page 1"
123+
124+
expect(page).to have_text "Hello from matestack with turbolinks - Page 1"
125+
126+
click_button "Transition to Page 2"
127+
128+
expect(page).to have_text "Hello from matestack with turbolinks - Page 2"
129+
130+
click_button "Link to Page 1"
131+
132+
expect(page).to have_text "Hello from matestack with turbolinks - Page 1"
133+
134+
visit "/turbolinks3"
135+
136+
expect(page).to have_text "Hello from matestack with turbolinks - Page 3"
137+
138+
expect_any_instance_of(ActionTestController).to receive(:expect_params)
139+
.with(hash_including(:foo => "bar"))
140+
141+
click_button "click me"
142+
143+
expect(page).to have_text "Hello from matestack with turbolinks - Page 3"
144+
end
145+
end

0 commit comments

Comments
 (0)