sinatra-kagero 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/sinatra/kagero/runtime.rb +92 -17
- data/lib/sinatra/kagero/version.rb +1 -1
- data/runtime/kagero.js +100 -20
- metadata +3 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2d24a386e65a603a75eb521362caec745f0f922a1823019c461a40234c5e1ce
|
|
4
|
+
data.tar.gz: 44f6627eb0b1764478386a37df1b43810153a920a3a32f8384b7c85404be172e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 13021231a7a1b035bba99546bdad6b8be9b927a277abc29f2d3abafe27aab26f3b09cf7987c68459aaecbec59208e3a0b7bdea1fa4dde32d48dd90b7d5ad856e
|
|
7
|
+
data.tar.gz: 167ad169bc9e924bbe47a18f4c5d4012e4a4b6caf62d00492b908a9e0a5d8be7bff4e848563b4da4563c34a685b28da893eae815ad25733c6c7e056db6e5569e
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,76 @@ module Sinatra
|
|
|
7
7
|
const root = document.querySelector("[data-kagero-root]");
|
|
8
8
|
let currentPage = null;
|
|
9
9
|
let currentScroll = { left: 0, top: 0 };
|
|
10
|
+
let pendingVisits = 0;
|
|
11
|
+
let loadingBar = null;
|
|
12
|
+
|
|
13
|
+
function ensureLoadingBar() {
|
|
14
|
+
if (loadingBar) return loadingBar;
|
|
15
|
+
|
|
16
|
+
const style = document.createElement("style");
|
|
17
|
+
style.textContent = `
|
|
18
|
+
#kagero-loading-bar {
|
|
19
|
+
position: fixed;
|
|
20
|
+
top: 0;
|
|
21
|
+
left: 0;
|
|
22
|
+
right: 0;
|
|
23
|
+
z-index: 2147483647;
|
|
24
|
+
height: 3px;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
pointer-events: none;
|
|
27
|
+
opacity: 0;
|
|
28
|
+
background: rgba(147, 197, 253, 0.24);
|
|
29
|
+
transition: opacity 120ms ease;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#kagero-loading-bar[data-active="true"] {
|
|
33
|
+
opacity: 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#kagero-loading-bar::before {
|
|
37
|
+
content: "";
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 0;
|
|
40
|
+
bottom: 0;
|
|
41
|
+
left: 0;
|
|
42
|
+
width: 48%;
|
|
43
|
+
background: linear-gradient(
|
|
44
|
+
90deg,
|
|
45
|
+
rgba(59, 130, 246, 0),
|
|
46
|
+
rgba(96, 165, 250, 0.35),
|
|
47
|
+
rgba(37, 99, 235, 0.9),
|
|
48
|
+
rgba(96, 165, 250, 0.35),
|
|
49
|
+
rgba(59, 130, 246, 0)
|
|
50
|
+
);
|
|
51
|
+
transform: translateX(-120%);
|
|
52
|
+
animation: kagero-loading-wave 700ms linear infinite;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@keyframes kagero-loading-wave {
|
|
56
|
+
from { transform: translateX(-120%); }
|
|
57
|
+
to { transform: translateX(260%); }
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
document.head.appendChild(style);
|
|
61
|
+
|
|
62
|
+
loadingBar = document.createElement("div");
|
|
63
|
+
loadingBar.id = "kagero-loading-bar";
|
|
64
|
+
loadingBar.setAttribute("aria-hidden", "true");
|
|
65
|
+
document.body.appendChild(loadingBar);
|
|
66
|
+
return loadingBar;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function startLoading() {
|
|
70
|
+
pendingVisits += 1;
|
|
71
|
+
ensureLoadingBar().dataset.active = "true";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function finishLoading() {
|
|
75
|
+
pendingVisits = Math.max(0, pendingVisits - 1);
|
|
76
|
+
if (pendingVisits === 0 && loadingBar) {
|
|
77
|
+
loadingBar.dataset.active = "false";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
10
80
|
|
|
11
81
|
function readInitialPage() {
|
|
12
82
|
if (!root) return null;
|
|
@@ -42,32 +112,37 @@ module Sinatra
|
|
|
42
112
|
|
|
43
113
|
async function visit(url, options = {}) {
|
|
44
114
|
rememberScroll();
|
|
115
|
+
startLoading();
|
|
45
116
|
const headers = new Headers(options.headers || {});
|
|
46
117
|
headers.set("X-Inertia", "true");
|
|
47
118
|
headers.set("X-Inertia-Version", currentPage ? currentPage.version : "");
|
|
48
119
|
headers.set("X-Requested-With", "XMLHttpRequest");
|
|
49
120
|
headers.set("Accept", "application/json, text/html;q=0.9");
|
|
50
121
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
122
|
+
try {
|
|
123
|
+
const response = await fetch(url, {
|
|
124
|
+
method: options.method || "GET",
|
|
125
|
+
body: options.body,
|
|
126
|
+
headers,
|
|
127
|
+
credentials: "same-origin",
|
|
128
|
+
redirect: "follow"
|
|
129
|
+
});
|
|
58
130
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
131
|
+
if (response.status === 409 && response.headers.get("X-Inertia-Location")) {
|
|
132
|
+
location.href = response.headers.get("X-Inertia-Location");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
63
135
|
|
|
64
|
-
|
|
136
|
+
if (!response.ok) throw new Error(`Kagero visit failed: ${response.status}`);
|
|
65
137
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
138
|
+
const page = await response.json();
|
|
139
|
+
applyPage(page, {
|
|
140
|
+
replace: options.replace === true,
|
|
141
|
+
preserveScroll: options.preserveScroll === true
|
|
142
|
+
});
|
|
143
|
+
} finally {
|
|
144
|
+
finishLoading();
|
|
145
|
+
}
|
|
71
146
|
}
|
|
72
147
|
|
|
73
148
|
function formBody(form) {
|
data/runtime/kagero.js
CHANGED
|
@@ -2,6 +2,76 @@ const root = document.querySelector("[data-kagero-root]");
|
|
|
2
2
|
|
|
3
3
|
let currentPage = null;
|
|
4
4
|
let currentScroll = { left: 0, top: 0 };
|
|
5
|
+
let pendingVisits = 0;
|
|
6
|
+
let loadingBar = null;
|
|
7
|
+
|
|
8
|
+
function ensureLoadingBar() {
|
|
9
|
+
if (loadingBar) return loadingBar;
|
|
10
|
+
|
|
11
|
+
const style = document.createElement("style");
|
|
12
|
+
style.textContent = `
|
|
13
|
+
#kagero-loading-bar {
|
|
14
|
+
position: fixed;
|
|
15
|
+
top: 0;
|
|
16
|
+
left: 0;
|
|
17
|
+
right: 0;
|
|
18
|
+
z-index: 2147483647;
|
|
19
|
+
height: 3px;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
opacity: 0;
|
|
23
|
+
background: rgba(147, 197, 253, 0.24);
|
|
24
|
+
transition: opacity 120ms ease;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#kagero-loading-bar[data-active="true"] {
|
|
28
|
+
opacity: 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#kagero-loading-bar::before {
|
|
32
|
+
content: "";
|
|
33
|
+
position: absolute;
|
|
34
|
+
top: 0;
|
|
35
|
+
bottom: 0;
|
|
36
|
+
left: 0;
|
|
37
|
+
width: 48%;
|
|
38
|
+
background: linear-gradient(
|
|
39
|
+
90deg,
|
|
40
|
+
rgba(59, 130, 246, 0),
|
|
41
|
+
rgba(96, 165, 250, 0.35),
|
|
42
|
+
rgba(37, 99, 235, 0.9),
|
|
43
|
+
rgba(96, 165, 250, 0.35),
|
|
44
|
+
rgba(59, 130, 246, 0)
|
|
45
|
+
);
|
|
46
|
+
transform: translateX(-120%);
|
|
47
|
+
animation: kagero-loading-wave 700ms linear infinite;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@keyframes kagero-loading-wave {
|
|
51
|
+
from { transform: translateX(-120%); }
|
|
52
|
+
to { transform: translateX(260%); }
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
document.head.appendChild(style);
|
|
56
|
+
|
|
57
|
+
loadingBar = document.createElement("div");
|
|
58
|
+
loadingBar.id = "kagero-loading-bar";
|
|
59
|
+
loadingBar.setAttribute("aria-hidden", "true");
|
|
60
|
+
document.body.appendChild(loadingBar);
|
|
61
|
+
return loadingBar;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function startLoading() {
|
|
65
|
+
pendingVisits += 1;
|
|
66
|
+
ensureLoadingBar().dataset.active = "true";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function finishLoading() {
|
|
70
|
+
pendingVisits = Math.max(0, pendingVisits - 1);
|
|
71
|
+
if (pendingVisits === 0 && loadingBar) {
|
|
72
|
+
loadingBar.dataset.active = "false";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
5
75
|
|
|
6
76
|
function readInitialPage() {
|
|
7
77
|
if (!root) return null;
|
|
@@ -37,32 +107,37 @@ function applyPage(page, { replace = false, preserveScroll = false } = {}) {
|
|
|
37
107
|
|
|
38
108
|
async function visit(url, options = {}) {
|
|
39
109
|
rememberScroll();
|
|
110
|
+
startLoading();
|
|
40
111
|
const headers = new Headers(options.headers || {});
|
|
41
112
|
headers.set("X-Inertia", "true");
|
|
42
113
|
headers.set("X-Inertia-Version", currentPage ? currentPage.version : "");
|
|
43
114
|
headers.set("X-Requested-With", "XMLHttpRequest");
|
|
44
115
|
headers.set("Accept", "application/json, text/html;q=0.9");
|
|
45
116
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
117
|
+
try {
|
|
118
|
+
const response = await fetch(url, {
|
|
119
|
+
method: options.method || "GET",
|
|
120
|
+
body: options.body,
|
|
121
|
+
headers,
|
|
122
|
+
credentials: "same-origin",
|
|
123
|
+
redirect: "follow"
|
|
124
|
+
});
|
|
53
125
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
126
|
+
if (response.status === 409 && response.headers.get("X-Inertia-Location")) {
|
|
127
|
+
location.href = response.headers.get("X-Inertia-Location");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
58
130
|
|
|
59
|
-
|
|
131
|
+
if (!response.ok) throw new Error(`Kagero visit failed: ${response.status}`);
|
|
60
132
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
133
|
+
const page = await response.json();
|
|
134
|
+
applyPage(page, {
|
|
135
|
+
replace: options.replace === true,
|
|
136
|
+
preserveScroll: options.preserveScroll === true
|
|
137
|
+
});
|
|
138
|
+
} finally {
|
|
139
|
+
finishLoading();
|
|
140
|
+
}
|
|
66
141
|
}
|
|
67
142
|
|
|
68
143
|
function formBody(form) {
|
|
@@ -83,7 +158,10 @@ function formUrl(form) {
|
|
|
83
158
|
}
|
|
84
159
|
|
|
85
160
|
document.addEventListener("click", (event) => {
|
|
86
|
-
const
|
|
161
|
+
const target = event.target;
|
|
162
|
+
if (!target || !target.closest) return;
|
|
163
|
+
|
|
164
|
+
const link = target.closest("a[data-kagero]");
|
|
87
165
|
if (link) {
|
|
88
166
|
event.preventDefault();
|
|
89
167
|
visit(link.href, {
|
|
@@ -93,7 +171,7 @@ document.addEventListener("click", (event) => {
|
|
|
93
171
|
return;
|
|
94
172
|
}
|
|
95
173
|
|
|
96
|
-
const reload =
|
|
174
|
+
const reload = target.closest("[data-kagero-reload]");
|
|
97
175
|
if (reload) {
|
|
98
176
|
event.preventDefault();
|
|
99
177
|
const only = reload.dataset.kageroOnly || "";
|
|
@@ -107,7 +185,9 @@ document.addEventListener("click", (event) => {
|
|
|
107
185
|
});
|
|
108
186
|
|
|
109
187
|
document.addEventListener("submit", (event) => {
|
|
110
|
-
const
|
|
188
|
+
const target = event.target;
|
|
189
|
+
if (!target || !target.closest) return;
|
|
190
|
+
const form = target.closest("form[data-kagero]");
|
|
111
191
|
if (!form) return;
|
|
112
192
|
|
|
113
193
|
event.preventDefault();
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sinatra-kagero
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kazuhiro Homma
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: sinatra-inertia
|
|
@@ -75,7 +74,6 @@ description: |
|
|
|
75
74
|
Phlex page classes, Literal-style props schemas, Ruby form/command
|
|
76
75
|
validation, and a hidden browser runtime for SPA-like navigation without
|
|
77
76
|
exposing JavaScript as the primary userland authoring model.
|
|
78
|
-
email:
|
|
79
77
|
executables: []
|
|
80
78
|
extensions: []
|
|
81
79
|
extra_rdoc_files: []
|
|
@@ -100,7 +98,6 @@ metadata:
|
|
|
100
98
|
changelog_uri: https://github.com/kazuph/homura/blob/main/gems/sinatra-kagero/CHANGELOG.md
|
|
101
99
|
readme_uri: https://github.com/kazuph/homura/blob/main/gems/sinatra-kagero/README.md
|
|
102
100
|
homura.auto_await: 'true'
|
|
103
|
-
post_install_message:
|
|
104
101
|
rdoc_options: []
|
|
105
102
|
require_paths:
|
|
106
103
|
- lib
|
|
@@ -115,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
115
112
|
- !ruby/object:Gem::Version
|
|
116
113
|
version: '0'
|
|
117
114
|
requirements: []
|
|
118
|
-
rubygems_version: 3.
|
|
119
|
-
signing_key:
|
|
115
|
+
rubygems_version: 3.6.9
|
|
120
116
|
specification_version: 4
|
|
121
117
|
summary: Ruby-way Inertia experience for Sinatra and Homura
|
|
122
118
|
test_files: []
|