overlastic 0.3.0 → 0.5.0
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/README.md +33 -3
- data/app/assets/javascripts/overlastic.js +48 -17
- data/app/assets/javascripts/overlastic.min.js +1 -1
- data/app/assets/javascripts/overlastic.min.js.map +1 -1
- data/app/controllers/overlastic/concerns/overlay_handling.rb +86 -1
- data/app/helpers/overlastic/overlays_helper.rb +18 -2
- data/app/javascript/overlastic/clickInterceptor.js +57 -21
- data/app/views/overlastic/inline/_dialog.html.erb +1 -3
- data/app/views/overlastic/inline/_pane.html.erb +1 -3
- data/app/views/overlastic/streams/redirect.turbo_stream.erb +10 -0
- data/app/views/overlastic/tailwind/_dialog.html.erb +1 -3
- data/app/views/overlastic/tailwind/_pane.html.erb +1 -3
- data/lib/overlastic/configuration.rb +2 -1
- data/lib/overlastic/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 000031e1d3c0946e9dad422d38c80b0c0b435944760344058628fb370348e016
|
4
|
+
data.tar.gz: 68c7bdd17baa0654ff3a0a5488f31b66b44c7d5f47dcaff10b3441090babe00c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e84e7a3e46e33828ef1fcac7e3d8ad9f42fd143c1b4d8af63365e8a526f03bdcce42a0e4e8f14b9dbc0e4c1683511e0403cb25f1694161cc75f5801f9540082
|
7
|
+
data.tar.gz: 274872a7b49569d6e8af1efc3d2b4ad2713753e64bb979bd2d1d04b45b28c6e2650c3875fb1a8b18ed997922041ffe4bf7a6af5a4e83b97ef7ec8c5ed3e9dfd1
|
data/README.md
CHANGED
@@ -45,12 +45,41 @@ By default, links and forms inside an overlay will drive the entire page (target
|
|
45
45
|
<%= link_to_dialog "Open dialog", edit_article_path, overlay_target: :_self %>
|
46
46
|
```
|
47
47
|
|
48
|
-
|
48
|
+
A common use case is to render a form inside an overlay. When the form is submitted, you'll validate the data and redirect to a different page if it's successful or render the form again with errors. Overlastic will handle both cases gracefully without any modifications:
|
49
|
+
|
50
|
+
```rb
|
51
|
+
if @article.save
|
52
|
+
redirect_to article_url(@article), status: :see_other
|
53
|
+
else
|
54
|
+
render :new, status: :unprocessable_entity
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
In case the form overlay was nested inside another overlay, you could prefer to apply the redirection to the parent overlay:
|
59
|
+
|
60
|
+
```rb
|
61
|
+
redirect_to article_url(@article), overlay: :previous, status: :see_other
|
62
|
+
```
|
63
|
+
|
64
|
+
Sometimes, you may want to alter the content of a view depending on whether it's inside an overlay or not. Overlastic defines a new `:overlay` request variant that you can use to create custom partials like `_form.html+overlay.erb` or inside a controller like so:
|
49
65
|
|
50
66
|
```rb
|
51
67
|
respond_to do |format|
|
52
68
|
format.html.overlay { render :custom_view }
|
53
|
-
format.html
|
69
|
+
format.html.any
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
You can also close overlays from the server if you don't need to render any more content:
|
74
|
+
|
75
|
+
```rb
|
76
|
+
if request.variant.overlay?
|
77
|
+
close_overlay
|
78
|
+
# close_overlay :last
|
79
|
+
# close_overlay :all
|
80
|
+
# close_overlay :overlay2
|
81
|
+
else
|
82
|
+
redirect_to articles_url, status: :see_other
|
54
83
|
end
|
55
84
|
```
|
56
85
|
|
@@ -64,6 +93,7 @@ Overlastic.configure do |config|
|
|
64
93
|
config.overlay_types = %i[dialog pane]
|
65
94
|
config.default_overlay = :dialog
|
66
95
|
config.default_action = :stack
|
96
|
+
config.default_target = :_top
|
67
97
|
|
68
98
|
# You can define a custom partial for each overlay type
|
69
99
|
config.dialog_overlay_view_path = "shared/overlays/dialog"
|
@@ -101,7 +131,7 @@ Overlastic comes with default views for both the dialog and pane overlays. It al
|
|
101
131
|
<details>
|
102
132
|
<summary>Roadmap</summary><br>
|
103
133
|
|
104
|
-
-
|
134
|
+
- Toasts?
|
105
135
|
</details>
|
106
136
|
|
107
137
|
<details>
|
@@ -203,34 +203,65 @@ var enableBodyScroll$1 = function enableBodyScroll(targetElement) {
|
|
203
203
|
};
|
204
204
|
|
205
205
|
addEventListener("click", (event => {
|
206
|
-
window.
|
207
|
-
}));
|
208
|
-
|
209
|
-
addEventListener("click", (_event => {
|
210
|
-
if (!window._overlasticClickedElement) return;
|
211
|
-
const target = window._overlasticClickedElement.dataset.overlayTarget;
|
212
|
-
const frame = document.querySelector(`turbo-frame#${window._overlasticClickedElement.dataset.turboFrame}`);
|
213
|
-
if (target === "_self") {
|
214
|
-
frame.removeAttribute("target");
|
215
|
-
} else {
|
216
|
-
frame.setAttribute("target", "_top");
|
217
|
-
}
|
218
|
-
}));
|
206
|
+
window._overlasticAnchor = event.target.closest("a[data-turbo-frame^=overlay]");
|
207
|
+
}), true);
|
219
208
|
|
220
209
|
addEventListener("turbo:before-fetch-request", (event => {
|
221
|
-
if (!window.
|
222
|
-
const
|
223
|
-
const type =
|
224
|
-
const
|
210
|
+
if (!window._overlasticAnchor) return;
|
211
|
+
const anchor = window._overlasticAnchor;
|
212
|
+
const type = anchor?.dataset?.overlayType;
|
213
|
+
const target = anchor?.dataset?.overlayTarget;
|
214
|
+
const args = anchor?.dataset?.overlayArgs;
|
215
|
+
event.detail.fetchOptions.headers["Overlay-Initiator"] = "1";
|
225
216
|
if (type) {
|
226
217
|
event.detail.fetchOptions.headers["Overlay-Type"] = type;
|
227
218
|
}
|
219
|
+
if (target) {
|
220
|
+
event.detail.fetchOptions.headers["Overlay-Target"] = target;
|
221
|
+
}
|
228
222
|
if (args) {
|
229
223
|
event.detail.fetchOptions.headers["Overlay-Args"] = args;
|
230
224
|
}
|
231
225
|
delete window._overlasticTarget;
|
232
226
|
}));
|
233
227
|
|
228
|
+
addEventListener("turbo:before-fetch-request", (event => {
|
229
|
+
if (window._overlasticAnchor) return;
|
230
|
+
const frame = event.target.closest("turbo-frame[id^=overlay]");
|
231
|
+
if (frame) {
|
232
|
+
const target = frame.dataset.overlayTarget;
|
233
|
+
const initiator = frame.dataset?.overlayInitiator;
|
234
|
+
const type = frame.dataset?.overlayType;
|
235
|
+
const args = frame.dataset?.overlayArgs;
|
236
|
+
event.detail.fetchOptions.headers["Overlay-Target"] = target;
|
237
|
+
if (initiator) {
|
238
|
+
event.detail.fetchOptions.headers["Overlay-Initiator"] = initiator;
|
239
|
+
}
|
240
|
+
if (type) {
|
241
|
+
event.detail.fetchOptions.headers["Overlay-Type"] = type;
|
242
|
+
}
|
243
|
+
if (args) {
|
244
|
+
event.detail.fetchOptions.headers["Overlay-Args"] = args;
|
245
|
+
}
|
246
|
+
}
|
247
|
+
}));
|
248
|
+
|
249
|
+
addEventListener("turbo:before-fetch-response", (async event => {
|
250
|
+
const fetchResponse = event.detail.fetchResponse;
|
251
|
+
const visit = fetchResponse.response.headers.get("Overlay-Visit");
|
252
|
+
if (!visit) return;
|
253
|
+
const responseHTML = await fetchResponse.responseHTML;
|
254
|
+
const {redirected: redirected, statusCode: statusCode} = fetchResponse;
|
255
|
+
return Turbo.session.visit(visit, {
|
256
|
+
shouldCacheSnapshot: false,
|
257
|
+
response: {
|
258
|
+
redirected: redirected,
|
259
|
+
statusCode: statusCode,
|
260
|
+
responseHTML: responseHTML
|
261
|
+
}
|
262
|
+
});
|
263
|
+
}));
|
264
|
+
|
234
265
|
class DialogElement extends HTMLElement {
|
235
266
|
connectedCallback() {
|
236
267
|
disableBodyScroll(this);
|
@@ -1,2 +1,2 @@
|
|
1
|
-
var e=!1;if("undefined"!=typeof window){var t={get passive(){e=!0}};window.addEventListener("testPassive",null,t),window.removeEventListener("testPassive",null,t)}var o="undefined"!=typeof window&&window.navigator&&window.navigator.platform&&(/iP(ad|hone|od)/.test(window.navigator.platform)||"MacIntel"===window.navigator.platform&&window.navigator.maxTouchPoints>1),n=[],i=!1,r=-1,
|
1
|
+
var e=!1;if("undefined"!=typeof window){var t={get passive(){e=!0}};window.addEventListener("testPassive",null,t),window.removeEventListener("testPassive",null,t)}var o="undefined"!=typeof window&&window.navigator&&window.navigator.platform&&(/iP(ad|hone|od)/.test(window.navigator.platform)||"MacIntel"===window.navigator.platform&&window.navigator.maxTouchPoints>1),n=[],i=!1,r=-1,s=void 0,a=void 0,d=void 0,l=function(e){return n.some((function(t){return!(!t.options.allowTouchMove||!t.options.allowTouchMove(e))}))},c=function(e){var t=e||window.event;return!!l(t.target)||(t.touches.length>1||(t.preventDefault&&t.preventDefault(),!1))};addEventListener("click",(e=>{window._overlasticAnchor=e.target.closest("a[data-turbo-frame^=overlay]")}),!0),addEventListener("turbo:before-fetch-request",(e=>{if(!window._overlasticAnchor)return;const t=window._overlasticAnchor,o=t?.dataset?.overlayType,n=t?.dataset?.overlayTarget,i=t?.dataset?.overlayArgs;e.detail.fetchOptions.headers["Overlay-Initiator"]="1",o&&(e.detail.fetchOptions.headers["Overlay-Type"]=o),n&&(e.detail.fetchOptions.headers["Overlay-Target"]=n),i&&(e.detail.fetchOptions.headers["Overlay-Args"]=i),delete window._overlasticTarget})),addEventListener("turbo:before-fetch-request",(e=>{if(window._overlasticAnchor)return;const t=e.target.closest("turbo-frame[id^=overlay]");if(t){const o=t.dataset.overlayTarget,n=t.dataset?.overlayInitiator,i=t.dataset?.overlayType,r=t.dataset?.overlayArgs;e.detail.fetchOptions.headers["Overlay-Target"]=o,n&&(e.detail.fetchOptions.headers["Overlay-Initiator"]=n),i&&(e.detail.fetchOptions.headers["Overlay-Type"]=i),r&&(e.detail.fetchOptions.headers["Overlay-Args"]=r)}})),addEventListener("turbo:before-fetch-response",(async e=>{const t=e.detail.fetchResponse,o=t.response.headers.get("Overlay-Visit");if(!o)return;const n=await t.responseHTML,{redirected:i,statusCode:r}=t;return Turbo.session.visit(o,{shouldCacheSnapshot:!1,response:{redirected:i,statusCode:r,responseHTML:n}})}));class u extends HTMLElement{connectedCallback(){disableBodyScroll(this),this.addEventListener("click",(e=>this.close(e,!0))),this.querySelector(".overlastic-close").addEventListener("click",(e=>this.close(e)))}close(e,t=!1){t&&e.target!==this||(enableBodyScroll(this),setTimeout((()=>{this.remove()}),5))}}customElements.define("overlastic-dialog",u);customElements.define("overlastic-pane",class extends u{connectedCallback(){super.connectedCallback();const e=Turbo.navigator.history.location;window.modalVisitStack||(window.modalVisitStack=[]),window.modalVisitStack.push(e),Turbo.navigator.history.push(new URL(this.parentElement.src))}close(e,t=!1){t&&e.target!==this||(super.close(e,t),window.modalVisitStack.length>0&&Turbo.navigator.history.replace(window.modalVisitStack.pop()))}}),window.disableBodyScroll=function(t,u){if(t){if(!n.some((function(e){return e.targetElement===t}))){var v={targetElement:t,options:u||{}};n=[].concat(function(e){if(Array.isArray(e)){for(var t=0,o=Array(e.length);t<e.length;t++)o[t]=e[t];return o}return Array.from(e)}(n),[v]),o?window.requestAnimationFrame((function(){if(void 0===a){a={position:document.body.style.position,top:document.body.style.top,left:document.body.style.left};var e=window,t=e.scrollY,o=e.scrollX,n=e.innerHeight;document.body.style.position="fixed",document.body.style.top=-t,document.body.style.left=-o,setTimeout((function(){return window.requestAnimationFrame((function(){var e=n-window.innerHeight;e&&t>=n&&(document.body.style.top=-(t+e))}))}),300)}})):function(e){if(void 0===d){var t=!!e&&!0===e.reserveScrollBarGap,o=window.innerWidth-document.documentElement.clientWidth;if(t&&o>0){var n=parseInt(window.getComputedStyle(document.body).getPropertyValue("padding-right"),10);d=document.body.style.paddingRight,document.body.style.paddingRight=n+o+"px"}}void 0===s&&(s=document.body.style.overflow,document.body.style.overflow="hidden")}(u),o&&(t.ontouchstart=function(e){1===e.targetTouches.length&&(r=e.targetTouches[0].clientY)},t.ontouchmove=function(e){1===e.targetTouches.length&&function(e,t){var o=e.targetTouches[0].clientY-r;!l(e.target)&&(t&&0===t.scrollTop&&o>0||function(e){return!!e&&e.scrollHeight-e.scrollTop<=e.clientHeight}(t)&&o<0?c(e):e.stopPropagation())}(e,t)},i||(document.addEventListener("touchmove",c,e?{passive:!1}:void 0),i=!0))}}else console.error("disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.")},window.enableBodyScroll=function(t){t?(n=n.filter((function(e){return e.targetElement!==t})),o&&(t.ontouchstart=null,t.ontouchmove=null,i&&0===n.length&&(document.removeEventListener("touchmove",c,e?{passive:!1}:void 0),i=!1)),o?function(){if(void 0!==a){var e=-parseInt(document.body.style.top,10),t=-parseInt(document.body.style.left,10);document.body.style.position=a.position,document.body.style.top=a.top,document.body.style.left=a.left,window.scrollTo(t,e),a=void 0}}():(void 0!==d&&(document.body.style.paddingRight=d,d=void 0),void 0!==s&&(document.body.style.overflow=s,s=void 0))):console.error("enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.")};
|
2
2
|
//# sourceMappingURL=overlastic.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"overlastic.min.js","sources":["../../../node_modules/body-scroll-lock/lib/bodyScrollLock.esm.js","../../javascript/overlastic/clickInterceptor.js","../../javascript/overlastic/dialogElement.js","../../javascript/overlastic/paneElement.js","../../javascript/overlastic/index.js"],"sourcesContent":["function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\n// Older browsers don't support event options, feature detect it.\n\n// Adopted and modified solution from Bohdan Didukh (2017)\n// https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi\n\nvar hasPassiveEvents = false;\nif (typeof window !== 'undefined') {\n var passiveTestOptions = {\n get passive() {\n hasPassiveEvents = true;\n return undefined;\n }\n };\n window.addEventListener('testPassive', null, passiveTestOptions);\n window.removeEventListener('testPassive', null, passiveTestOptions);\n}\n\nvar isIosDevice = typeof window !== 'undefined' && window.navigator && window.navigator.platform && (/iP(ad|hone|od)/.test(window.navigator.platform) || window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1);\n\n\nvar locks = [];\nvar documentListenerAdded = false;\nvar initialClientY = -1;\nvar previousBodyOverflowSetting = void 0;\nvar previousBodyPosition = void 0;\nvar previousBodyPaddingRight = void 0;\n\n// returns true if `el` should be allowed to receive touchmove events.\nvar allowTouchMove = function allowTouchMove(el) {\n return locks.some(function (lock) {\n if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {\n return true;\n }\n\n return false;\n });\n};\n\nvar preventDefault = function preventDefault(rawEvent) {\n var e = rawEvent || window.event;\n\n // For the case whereby consumers adds a touchmove event listener to document.\n // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })\n // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then\n // the touchmove event on document will break.\n if (allowTouchMove(e.target)) {\n return true;\n }\n\n // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n if (e.touches.length > 1) return true;\n\n if (e.preventDefault) e.preventDefault();\n\n return false;\n};\n\nvar setOverflowHidden = function setOverflowHidden(options) {\n // If previousBodyPaddingRight is already set, don't set it again.\n if (previousBodyPaddingRight === undefined) {\n var _reserveScrollBarGap = !!options && options.reserveScrollBarGap === true;\n var scrollBarGap = window.innerWidth - document.documentElement.clientWidth;\n\n if (_reserveScrollBarGap && scrollBarGap > 0) {\n var computedBodyPaddingRight = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'), 10);\n previousBodyPaddingRight = document.body.style.paddingRight;\n document.body.style.paddingRight = computedBodyPaddingRight + scrollBarGap + 'px';\n }\n }\n\n // If previousBodyOverflowSetting is already set, don't set it again.\n if (previousBodyOverflowSetting === undefined) {\n previousBodyOverflowSetting = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n};\n\nvar restoreOverflowSetting = function restoreOverflowSetting() {\n if (previousBodyPaddingRight !== undefined) {\n document.body.style.paddingRight = previousBodyPaddingRight;\n\n // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it\n // can be set again.\n previousBodyPaddingRight = undefined;\n }\n\n if (previousBodyOverflowSetting !== undefined) {\n document.body.style.overflow = previousBodyOverflowSetting;\n\n // Restore previousBodyOverflowSetting to undefined\n // so setOverflowHidden knows it can be set again.\n previousBodyOverflowSetting = undefined;\n }\n};\n\nvar setPositionFixed = function setPositionFixed() {\n return window.requestAnimationFrame(function () {\n // If previousBodyPosition is already set, don't set it again.\n if (previousBodyPosition === undefined) {\n previousBodyPosition = {\n position: document.body.style.position,\n top: document.body.style.top,\n left: document.body.style.left\n };\n\n // Update the dom inside an animation frame \n var _window = window,\n scrollY = _window.scrollY,\n scrollX = _window.scrollX,\n innerHeight = _window.innerHeight;\n\n document.body.style.position = 'fixed';\n document.body.style.top = -scrollY;\n document.body.style.left = -scrollX;\n\n setTimeout(function () {\n return window.requestAnimationFrame(function () {\n // Attempt to check if the bottom bar appeared due to the position change\n var bottomBarHeight = innerHeight - window.innerHeight;\n if (bottomBarHeight && scrollY >= innerHeight) {\n // Move the content further up so that the bottom bar doesn't hide it\n document.body.style.top = -(scrollY + bottomBarHeight);\n }\n });\n }, 300);\n }\n });\n};\n\nvar restorePositionSetting = function restorePositionSetting() {\n if (previousBodyPosition !== undefined) {\n // Convert the position from \"px\" to Int\n var y = -parseInt(document.body.style.top, 10);\n var x = -parseInt(document.body.style.left, 10);\n\n // Restore styles\n document.body.style.position = previousBodyPosition.position;\n document.body.style.top = previousBodyPosition.top;\n document.body.style.left = previousBodyPosition.left;\n\n // Restore scroll\n window.scrollTo(x, y);\n\n previousBodyPosition = undefined;\n }\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\nvar isTargetElementTotallyScrolled = function isTargetElementTotallyScrolled(targetElement) {\n return targetElement ? targetElement.scrollHeight - targetElement.scrollTop <= targetElement.clientHeight : false;\n};\n\nvar handleScroll = function handleScroll(event, targetElement) {\n var clientY = event.targetTouches[0].clientY - initialClientY;\n\n if (allowTouchMove(event.target)) {\n return false;\n }\n\n if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {\n // element is at the top of its scroll.\n return preventDefault(event);\n }\n\n if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {\n // element is at the bottom of its scroll.\n return preventDefault(event);\n }\n\n event.stopPropagation();\n return true;\n};\n\nexport var disableBodyScroll = function disableBodyScroll(targetElement, options) {\n // targetElement must be provided\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error('disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.');\n return;\n }\n\n // disableBodyScroll must not have been called on this targetElement before\n if (locks.some(function (lock) {\n return lock.targetElement === targetElement;\n })) {\n return;\n }\n\n var lock = {\n targetElement: targetElement,\n options: options || {}\n };\n\n locks = [].concat(_toConsumableArray(locks), [lock]);\n\n if (isIosDevice) {\n setPositionFixed();\n } else {\n setOverflowHidden(options);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = function (event) {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n initialClientY = event.targetTouches[0].clientY;\n }\n };\n targetElement.ontouchmove = function (event) {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n handleScroll(event, targetElement);\n }\n };\n\n if (!documentListenerAdded) {\n document.addEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);\n documentListenerAdded = true;\n }\n }\n};\n\nexport var clearAllBodyScrollLocks = function clearAllBodyScrollLocks() {\n if (isIosDevice) {\n // Clear all locks ontouchstart/ontouchmove handlers, and the references.\n locks.forEach(function (lock) {\n lock.targetElement.ontouchstart = null;\n lock.targetElement.ontouchmove = null;\n });\n\n if (documentListenerAdded) {\n document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);\n documentListenerAdded = false;\n }\n\n // Reset initial clientY.\n initialClientY = -1;\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n\n locks = [];\n};\n\nexport var enableBodyScroll = function enableBodyScroll(targetElement) {\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error('enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.');\n return;\n }\n\n locks = locks.filter(function (lock) {\n return lock.targetElement !== targetElement;\n });\n\n if (isIosDevice) {\n targetElement.ontouchstart = null;\n targetElement.ontouchmove = null;\n\n if (documentListenerAdded && locks.length === 0) {\n document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);\n documentListenerAdded = false;\n }\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n};\n\n","// Save the clicked overlay link element for use down the line\naddEventListener(\"click\", event => {\n window._overlasticClickedElement = event.target.closest(\"[data-turbo-frame^=overlay]\")\n})\n\n// Set the correct target for the frame according to the desired behavior\naddEventListener(\"click\", _event => {\n if (!window._overlasticClickedElement) return\n\n const target = window._overlasticClickedElement.dataset.overlayTarget\n const frame = document.querySelector(`turbo-frame#${window._overlasticClickedElement.dataset.turboFrame}`)\n\n if (target === \"_self\") {\n frame.removeAttribute(\"target\")\n } else {\n frame.setAttribute(\"target\", \"_top\")\n }\n})\n\n// Send overlay type and args along with the frame request\naddEventListener(\"turbo:before-fetch-request\", event => {\n if (!window._overlasticClickedElement) return\n\n const target = window._overlasticClickedElement\n const type = target?.dataset?.overlayType\n const args = target?.dataset?.overlayArgs\n\n if (type) {\n event.detail.fetchOptions.headers[\"Overlay-Type\"] = type\n }\n\n if (args) {\n event.detail.fetchOptions.headers[\"Overlay-Args\"] = args\n }\n\n delete window._overlasticTarget\n})\n","export default class DialogElement extends HTMLElement {\n connectedCallback() {\n disableBodyScroll(this)\n\n this.addEventListener(\"click\", event => this.close(event, true))\n this.querySelector(\".overlastic-close\").addEventListener(\"click\", event => this.close(event))\n }\n\n close(event, self = false) {\n if (self && event.target !== this) return\n\n enableBodyScroll(this)\n\n // Avoid removing before sending dispatching other events (like form submissions)\n setTimeout(() => {\n this.remove()\n }, 5)\n }\n}\n\ncustomElements.define(\"overlastic-dialog\", DialogElement)\n","import DialogElement from \"./dialogElement\"\n\nclass PaneElement extends DialogElement {\n connectedCallback() {\n super.connectedCallback()\n\n const lastVisit = Turbo.navigator.history.location\n\n if (!window.modalVisitStack) {\n window.modalVisitStack = []\n }\n\n window.modalVisitStack.push(lastVisit)\n Turbo.navigator.history.push(new URL(this.parentElement.src))\n }\n\n close(event, self = false) {\n if (self && event.target !== this) return\n\n super.close(event, self)\n\n if (window.modalVisitStack.length > 0) {\n Turbo.navigator.history.replace(window.modalVisitStack.pop())\n }\n }\n}\n\ncustomElements.define(\"overlastic-pane\", PaneElement)\n","import { disableBodyScroll, enableBodyScroll } from \"body-scroll-lock\"\n\nimport \"./clickInterceptor\"\nimport \"./dialogElement\"\nimport \"./paneElement\"\n\nwindow.disableBodyScroll = disableBodyScroll\nwindow.enableBodyScroll = enableBodyScroll\n"],"names":["hasPassiveEvents","window","passiveTestOptions","passive","addEventListener","removeEventListener","isIosDevice","navigator","platform","test","maxTouchPoints","locks","documentListenerAdded","initialClientY","previousBodyOverflowSetting","previousBodyPosition","previousBodyPaddingRight","allowTouchMove","el","some","lock","options","preventDefault","rawEvent","e","event","target","touches","length","_overlasticClickedElement","closest","_event","dataset","overlayTarget","frame","document","querySelector","turboFrame","removeAttribute","setAttribute","type","overlayType","args","overlayArgs","detail","fetchOptions","headers","_overlasticTarget","DialogElement","HTMLElement","[object Object]","disableBodyScroll","this","close","self","enableBodyScroll","setTimeout","remove","customElements","define","super","connectedCallback","lastVisit","Turbo","history","location","modalVisitStack","push","URL","parentElement","src","replace","pop","targetElement","concat","arr","Array","isArray","i","arr2","from","_toConsumableArray","requestAnimationFrame","undefined","position","body","style","top","left","_window","scrollY","scrollX","innerHeight","bottomBarHeight","_reserveScrollBarGap","reserveScrollBarGap","scrollBarGap","innerWidth","documentElement","clientWidth","computedBodyPaddingRight","parseInt","getComputedStyle","getPropertyValue","paddingRight","overflow","setOverflowHidden","ontouchstart","targetTouches","clientY","ontouchmove","scrollTop","scrollHeight","clientHeight","isTargetElementTotallyScrolled","stopPropagation","handleScroll","console","error","filter","y","x","scrollTo","restorePositionSetting"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"overlastic.min.js","sources":["../../../node_modules/body-scroll-lock/lib/bodyScrollLock.esm.js","../../javascript/overlastic/clickInterceptor.js","../../javascript/overlastic/dialogElement.js","../../javascript/overlastic/paneElement.js","../../javascript/overlastic/index.js"],"sourcesContent":["function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\n// Older browsers don't support event options, feature detect it.\n\n// Adopted and modified solution from Bohdan Didukh (2017)\n// https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi\n\nvar hasPassiveEvents = false;\nif (typeof window !== 'undefined') {\n var passiveTestOptions = {\n get passive() {\n hasPassiveEvents = true;\n return undefined;\n }\n };\n window.addEventListener('testPassive', null, passiveTestOptions);\n window.removeEventListener('testPassive', null, passiveTestOptions);\n}\n\nvar isIosDevice = typeof window !== 'undefined' && window.navigator && window.navigator.platform && (/iP(ad|hone|od)/.test(window.navigator.platform) || window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1);\n\n\nvar locks = [];\nvar documentListenerAdded = false;\nvar initialClientY = -1;\nvar previousBodyOverflowSetting = void 0;\nvar previousBodyPosition = void 0;\nvar previousBodyPaddingRight = void 0;\n\n// returns true if `el` should be allowed to receive touchmove events.\nvar allowTouchMove = function allowTouchMove(el) {\n return locks.some(function (lock) {\n if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {\n return true;\n }\n\n return false;\n });\n};\n\nvar preventDefault = function preventDefault(rawEvent) {\n var e = rawEvent || window.event;\n\n // For the case whereby consumers adds a touchmove event listener to document.\n // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })\n // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then\n // the touchmove event on document will break.\n if (allowTouchMove(e.target)) {\n return true;\n }\n\n // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n if (e.touches.length > 1) return true;\n\n if (e.preventDefault) e.preventDefault();\n\n return false;\n};\n\nvar setOverflowHidden = function setOverflowHidden(options) {\n // If previousBodyPaddingRight is already set, don't set it again.\n if (previousBodyPaddingRight === undefined) {\n var _reserveScrollBarGap = !!options && options.reserveScrollBarGap === true;\n var scrollBarGap = window.innerWidth - document.documentElement.clientWidth;\n\n if (_reserveScrollBarGap && scrollBarGap > 0) {\n var computedBodyPaddingRight = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'), 10);\n previousBodyPaddingRight = document.body.style.paddingRight;\n document.body.style.paddingRight = computedBodyPaddingRight + scrollBarGap + 'px';\n }\n }\n\n // If previousBodyOverflowSetting is already set, don't set it again.\n if (previousBodyOverflowSetting === undefined) {\n previousBodyOverflowSetting = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n};\n\nvar restoreOverflowSetting = function restoreOverflowSetting() {\n if (previousBodyPaddingRight !== undefined) {\n document.body.style.paddingRight = previousBodyPaddingRight;\n\n // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it\n // can be set again.\n previousBodyPaddingRight = undefined;\n }\n\n if (previousBodyOverflowSetting !== undefined) {\n document.body.style.overflow = previousBodyOverflowSetting;\n\n // Restore previousBodyOverflowSetting to undefined\n // so setOverflowHidden knows it can be set again.\n previousBodyOverflowSetting = undefined;\n }\n};\n\nvar setPositionFixed = function setPositionFixed() {\n return window.requestAnimationFrame(function () {\n // If previousBodyPosition is already set, don't set it again.\n if (previousBodyPosition === undefined) {\n previousBodyPosition = {\n position: document.body.style.position,\n top: document.body.style.top,\n left: document.body.style.left\n };\n\n // Update the dom inside an animation frame \n var _window = window,\n scrollY = _window.scrollY,\n scrollX = _window.scrollX,\n innerHeight = _window.innerHeight;\n\n document.body.style.position = 'fixed';\n document.body.style.top = -scrollY;\n document.body.style.left = -scrollX;\n\n setTimeout(function () {\n return window.requestAnimationFrame(function () {\n // Attempt to check if the bottom bar appeared due to the position change\n var bottomBarHeight = innerHeight - window.innerHeight;\n if (bottomBarHeight && scrollY >= innerHeight) {\n // Move the content further up so that the bottom bar doesn't hide it\n document.body.style.top = -(scrollY + bottomBarHeight);\n }\n });\n }, 300);\n }\n });\n};\n\nvar restorePositionSetting = function restorePositionSetting() {\n if (previousBodyPosition !== undefined) {\n // Convert the position from \"px\" to Int\n var y = -parseInt(document.body.style.top, 10);\n var x = -parseInt(document.body.style.left, 10);\n\n // Restore styles\n document.body.style.position = previousBodyPosition.position;\n document.body.style.top = previousBodyPosition.top;\n document.body.style.left = previousBodyPosition.left;\n\n // Restore scroll\n window.scrollTo(x, y);\n\n previousBodyPosition = undefined;\n }\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\nvar isTargetElementTotallyScrolled = function isTargetElementTotallyScrolled(targetElement) {\n return targetElement ? targetElement.scrollHeight - targetElement.scrollTop <= targetElement.clientHeight : false;\n};\n\nvar handleScroll = function handleScroll(event, targetElement) {\n var clientY = event.targetTouches[0].clientY - initialClientY;\n\n if (allowTouchMove(event.target)) {\n return false;\n }\n\n if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {\n // element is at the top of its scroll.\n return preventDefault(event);\n }\n\n if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {\n // element is at the bottom of its scroll.\n return preventDefault(event);\n }\n\n event.stopPropagation();\n return true;\n};\n\nexport var disableBodyScroll = function disableBodyScroll(targetElement, options) {\n // targetElement must be provided\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error('disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.');\n return;\n }\n\n // disableBodyScroll must not have been called on this targetElement before\n if (locks.some(function (lock) {\n return lock.targetElement === targetElement;\n })) {\n return;\n }\n\n var lock = {\n targetElement: targetElement,\n options: options || {}\n };\n\n locks = [].concat(_toConsumableArray(locks), [lock]);\n\n if (isIosDevice) {\n setPositionFixed();\n } else {\n setOverflowHidden(options);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = function (event) {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n initialClientY = event.targetTouches[0].clientY;\n }\n };\n targetElement.ontouchmove = function (event) {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n handleScroll(event, targetElement);\n }\n };\n\n if (!documentListenerAdded) {\n document.addEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);\n documentListenerAdded = true;\n }\n }\n};\n\nexport var clearAllBodyScrollLocks = function clearAllBodyScrollLocks() {\n if (isIosDevice) {\n // Clear all locks ontouchstart/ontouchmove handlers, and the references.\n locks.forEach(function (lock) {\n lock.targetElement.ontouchstart = null;\n lock.targetElement.ontouchmove = null;\n });\n\n if (documentListenerAdded) {\n document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);\n documentListenerAdded = false;\n }\n\n // Reset initial clientY.\n initialClientY = -1;\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n\n locks = [];\n};\n\nexport var enableBodyScroll = function enableBodyScroll(targetElement) {\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error('enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.');\n return;\n }\n\n locks = locks.filter(function (lock) {\n return lock.targetElement !== targetElement;\n });\n\n if (isIosDevice) {\n targetElement.ontouchstart = null;\n targetElement.ontouchmove = null;\n\n if (documentListenerAdded && locks.length === 0) {\n document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);\n documentListenerAdded = false;\n }\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n};\n\n","// Save the clicked overlay link element for use down the line\naddEventListener(\"click\", event => {\n window._overlasticAnchor = event.target.closest(\"a[data-turbo-frame^=overlay]\")\n}, true)\n\n// When an overlay anchor is clicked,\n// send its type, target and args along with the frame request\naddEventListener(\"turbo:before-fetch-request\", event => {\n if (!window._overlasticAnchor) return\n\n const anchor = window._overlasticAnchor\n const type = anchor?.dataset?.overlayType\n const target = anchor?.dataset?.overlayTarget\n const args = anchor?.dataset?.overlayArgs\n\n event.detail.fetchOptions.headers[\"Overlay-Initiator\"] = \"1\"\n\n if (type) {\n event.detail.fetchOptions.headers[\"Overlay-Type\"] = type\n }\n\n if (target) {\n event.detail.fetchOptions.headers[\"Overlay-Target\"] = target\n }\n\n if (args) {\n event.detail.fetchOptions.headers[\"Overlay-Args\"] = args\n }\n\n delete window._overlasticTarget\n})\n\n// When any other element triggers a fetch,\n// send the current overlay's target along with the frame request\naddEventListener(\"turbo:before-fetch-request\", event => {\n if (window._overlasticAnchor) return\n\n const frame = event.target.closest(\"turbo-frame[id^=overlay]\")\n\n if (frame) {\n const target = frame.dataset.overlayTarget\n const initiator = frame.dataset?.overlayInitiator\n const type = frame.dataset?.overlayType\n const args = frame.dataset?.overlayArgs\n\n event.detail.fetchOptions.headers[\"Overlay-Target\"] = target\n\n if (initiator) {\n event.detail.fetchOptions.headers[\"Overlay-Initiator\"] = initiator\n }\n\n if (type) {\n event.detail.fetchOptions.headers[\"Overlay-Type\"] = type\n }\n\n if (args) {\n event.detail.fetchOptions.headers[\"Overlay-Args\"] = args\n }\n }\n})\n\n// Handle frame-to-visit promotions when the server asks for it\naddEventListener(\"turbo:before-fetch-response\", async event => {\n const fetchResponse = event.detail.fetchResponse\n const visit = fetchResponse.response.headers.get(\"Overlay-Visit\")\n\n if (!visit) return\n\n const responseHTML = await fetchResponse.responseHTML\n const { redirected, statusCode } = fetchResponse\n\n return Turbo.session.visit(visit, { shouldCacheSnapshot: false, response: { redirected, statusCode, responseHTML } })\n})\n","export default class DialogElement extends HTMLElement {\n connectedCallback() {\n disableBodyScroll(this)\n\n this.addEventListener(\"click\", event => this.close(event, true))\n this.querySelector(\".overlastic-close\").addEventListener(\"click\", event => this.close(event))\n }\n\n close(event, self = false) {\n if (self && event.target !== this) return\n\n enableBodyScroll(this)\n\n // Avoid removing before sending dispatching other events (like form submissions)\n setTimeout(() => {\n this.remove()\n }, 5)\n }\n}\n\ncustomElements.define(\"overlastic-dialog\", DialogElement)\n","import DialogElement from \"./dialogElement\"\n\nclass PaneElement extends DialogElement {\n connectedCallback() {\n super.connectedCallback()\n\n const lastVisit = Turbo.navigator.history.location\n\n if (!window.modalVisitStack) {\n window.modalVisitStack = []\n }\n\n window.modalVisitStack.push(lastVisit)\n Turbo.navigator.history.push(new URL(this.parentElement.src))\n }\n\n close(event, self = false) {\n if (self && event.target !== this) return\n\n super.close(event, self)\n\n if (window.modalVisitStack.length > 0) {\n Turbo.navigator.history.replace(window.modalVisitStack.pop())\n }\n }\n}\n\ncustomElements.define(\"overlastic-pane\", PaneElement)\n","import { disableBodyScroll, enableBodyScroll } from \"body-scroll-lock\"\n\nimport \"./clickInterceptor\"\nimport \"./dialogElement\"\nimport \"./paneElement\"\n\nwindow.disableBodyScroll = disableBodyScroll\nwindow.enableBodyScroll = enableBodyScroll\n"],"names":["hasPassiveEvents","window","passiveTestOptions","passive","addEventListener","removeEventListener","isIosDevice","navigator","platform","test","maxTouchPoints","locks","documentListenerAdded","initialClientY","previousBodyOverflowSetting","previousBodyPosition","previousBodyPaddingRight","allowTouchMove","el","some","lock","options","preventDefault","rawEvent","e","event","target","touches","length","_overlasticAnchor","closest","anchor","type","dataset","overlayType","overlayTarget","args","overlayArgs","detail","fetchOptions","headers","_overlasticTarget","frame","initiator","overlayInitiator","async","fetchResponse","visit","response","get","responseHTML","redirected","statusCode","Turbo","session","shouldCacheSnapshot","DialogElement","HTMLElement","[object Object]","disableBodyScroll","this","close","querySelector","self","enableBodyScroll","setTimeout","remove","customElements","define","super","connectedCallback","lastVisit","history","location","modalVisitStack","push","URL","parentElement","src","replace","pop","targetElement","concat","arr","Array","isArray","i","arr2","from","_toConsumableArray","requestAnimationFrame","undefined","position","document","body","style","top","left","_window","scrollY","scrollX","innerHeight","bottomBarHeight","_reserveScrollBarGap","reserveScrollBarGap","scrollBarGap","innerWidth","documentElement","clientWidth","computedBodyPaddingRight","parseInt","getComputedStyle","getPropertyValue","paddingRight","overflow","setOverflowHidden","ontouchstart","targetTouches","clientY","ontouchmove","scrollTop","scrollHeight","clientHeight","isTargetElementTotallyScrolled","stopPropagation","handleScroll","console","error","filter","y","x","scrollTo","restorePositionSetting"],"mappings":"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"}
|
@@ -10,9 +10,94 @@ module Overlastic::Concerns::OverlayHandling
|
|
10
10
|
request.variant = :overlay if helpers.current_overlay_name.present?
|
11
11
|
end
|
12
12
|
|
13
|
+
def close_overlay(name = :last)
|
14
|
+
name =
|
15
|
+
case name
|
16
|
+
when :all
|
17
|
+
:overlay1
|
18
|
+
when :last
|
19
|
+
helpers.current_overlay_name
|
20
|
+
else
|
21
|
+
name
|
22
|
+
end
|
23
|
+
|
24
|
+
render close_overlay: name
|
25
|
+
end
|
26
|
+
|
13
27
|
def render(*args, &block)
|
14
28
|
if request.variant.overlay?
|
15
|
-
|
29
|
+
options = args.last || {}
|
30
|
+
|
31
|
+
# Rendering with an error status should render inside the overlay
|
32
|
+
error = Rack::Utils.status_code(options[:status]).in? 400..499
|
33
|
+
|
34
|
+
# Initiator requests always render inside an overlay
|
35
|
+
initiator = request.headers["Overlay-Initiator"]
|
36
|
+
|
37
|
+
# By default, navigation inside the overlay will break out of it (_top)
|
38
|
+
target = request.headers["Overlay-Target"]
|
39
|
+
|
40
|
+
# Force visit to the desired redirection location
|
41
|
+
redirect = options[:redirect]
|
42
|
+
|
43
|
+
# Name of the overlay to be closed
|
44
|
+
close_overlay = options[:close_overlay]
|
45
|
+
|
46
|
+
if redirect
|
47
|
+
response.headers["Overlay-Visit"] = redirect
|
48
|
+
|
49
|
+
super turbo_stream: turbo_stream.replace(helpers.current_overlay_name, html: helpers.overlastic_tag(id: close_overlay))
|
50
|
+
elsif close_overlay
|
51
|
+
super turbo_stream: turbo_stream.replace(close_overlay, html: helpers.overlastic_tag(id: close_overlay))
|
52
|
+
elsif initiator || error || target != "_top"
|
53
|
+
super turbo_stream: turbo_stream.replace(helpers.current_overlay_name, html: helpers.render_overlay { render_to_string(*args, &block) })
|
54
|
+
else
|
55
|
+
request.headers["Turbo-Frame"] = nil
|
56
|
+
response.headers["Overlay-Visit"] = request.fullpath
|
57
|
+
|
58
|
+
super
|
59
|
+
end
|
60
|
+
else
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Based on https://github.com/hotwired/turbo-rails/pull/367
|
66
|
+
# by seanpdoyle
|
67
|
+
def redirect_to(options = {}, response_options = {})
|
68
|
+
location = url_for(options)
|
69
|
+
overlay = response_options.delete(:overlay)
|
70
|
+
overlay_name =
|
71
|
+
case overlay
|
72
|
+
when :current
|
73
|
+
helpers.current_overlay_name
|
74
|
+
when :previous
|
75
|
+
current_number = helpers.current_overlay_name.to_s.scan(/\d+/)&.first.to_i
|
76
|
+
|
77
|
+
"overlay#{current_number - 1}"
|
78
|
+
else
|
79
|
+
overlay
|
80
|
+
end
|
81
|
+
|
82
|
+
if request.variant.overlay?
|
83
|
+
if overlay_name.present?
|
84
|
+
unless helpers.valid_overlay_name? overlay_name
|
85
|
+
return render redirect: location
|
86
|
+
end
|
87
|
+
|
88
|
+
request.variant.delete(:overlay)
|
89
|
+
flash.merge! response_options.fetch(:flash, {})
|
90
|
+
|
91
|
+
case Rack::Utils.status_code(response_options.fetch(:status, :created))
|
92
|
+
when 300..399 then response_options[:status] = :created
|
93
|
+
end
|
94
|
+
|
95
|
+
render "overlastic/streams/redirect", response_options.with_defaults(
|
96
|
+
locals: { location: location, overlay: overlay_name }
|
97
|
+
)
|
98
|
+
else
|
99
|
+
super
|
100
|
+
end
|
16
101
|
else
|
17
102
|
super
|
18
103
|
end
|
@@ -1,6 +1,18 @@
|
|
1
1
|
module Overlastic::OverlaysHelper
|
2
|
-
def overlastic_tag
|
3
|
-
|
2
|
+
def overlastic_tag(id: :overlay1)
|
3
|
+
if block_given?
|
4
|
+
type = request.headers["Overlay-Type"]
|
5
|
+
target = request.headers["Overlay-Target"] || Overlastic.configuration.default_target
|
6
|
+
args = request.headers["Overlay-Args"]
|
7
|
+
|
8
|
+
turbo_frame_tag current_overlay_name, data: { overlay_type: type, overlay_target: target, overlay_args: args } do
|
9
|
+
yield
|
10
|
+
|
11
|
+
concat turbo_frame_tag(next_overlay_name, data: { overlay_target: Overlastic.configuration.default_target })
|
12
|
+
end
|
13
|
+
else
|
14
|
+
turbo_frame_tag id, data: { overlay_target: Overlastic.configuration.default_target }
|
15
|
+
end
|
4
16
|
end
|
5
17
|
|
6
18
|
def current_overlay_name
|
@@ -15,6 +27,10 @@ module Overlastic::OverlaysHelper
|
|
15
27
|
"overlay#{current_number + 1}".to_sym
|
16
28
|
end
|
17
29
|
|
30
|
+
def valid_overlay_name?(name)
|
31
|
+
name.to_s.scan(/\d+/)&.first&.to_i&.positive?
|
32
|
+
end
|
33
|
+
|
18
34
|
def render_overlay(locals = {}, &block)
|
19
35
|
string = capture(&block)
|
20
36
|
type = request.headers["Overlay-Type"] || Overlastic.configuration.default_overlay
|
@@ -1,37 +1,73 @@
|
|
1
1
|
// Save the clicked overlay link element for use down the line
|
2
2
|
addEventListener("click", event => {
|
3
|
-
window.
|
4
|
-
})
|
5
|
-
|
6
|
-
// Set the correct target for the frame according to the desired behavior
|
7
|
-
addEventListener("click", _event => {
|
8
|
-
if (!window._overlasticClickedElement) return
|
9
|
-
|
10
|
-
const target = window._overlasticClickedElement.dataset.overlayTarget
|
11
|
-
const frame = document.querySelector(`turbo-frame#${window._overlasticClickedElement.dataset.turboFrame}`)
|
12
|
-
|
13
|
-
if (target === "_self") {
|
14
|
-
frame.removeAttribute("target")
|
15
|
-
} else {
|
16
|
-
frame.setAttribute("target", "_top")
|
17
|
-
}
|
18
|
-
})
|
3
|
+
window._overlasticAnchor = event.target.closest("a[data-turbo-frame^=overlay]")
|
4
|
+
}, true)
|
19
5
|
|
20
|
-
//
|
6
|
+
// When an overlay anchor is clicked,
|
7
|
+
// send its type, target and args along with the frame request
|
21
8
|
addEventListener("turbo:before-fetch-request", event => {
|
22
|
-
if (!window.
|
9
|
+
if (!window._overlasticAnchor) return
|
23
10
|
|
24
|
-
const
|
25
|
-
const type =
|
26
|
-
const
|
11
|
+
const anchor = window._overlasticAnchor
|
12
|
+
const type = anchor?.dataset?.overlayType
|
13
|
+
const target = anchor?.dataset?.overlayTarget
|
14
|
+
const args = anchor?.dataset?.overlayArgs
|
15
|
+
|
16
|
+
event.detail.fetchOptions.headers["Overlay-Initiator"] = "1"
|
27
17
|
|
28
18
|
if (type) {
|
29
19
|
event.detail.fetchOptions.headers["Overlay-Type"] = type
|
30
20
|
}
|
31
21
|
|
22
|
+
if (target) {
|
23
|
+
event.detail.fetchOptions.headers["Overlay-Target"] = target
|
24
|
+
}
|
25
|
+
|
32
26
|
if (args) {
|
33
27
|
event.detail.fetchOptions.headers["Overlay-Args"] = args
|
34
28
|
}
|
35
29
|
|
36
30
|
delete window._overlasticTarget
|
37
31
|
})
|
32
|
+
|
33
|
+
// When any other element triggers a fetch,
|
34
|
+
// send the current overlay's target along with the frame request
|
35
|
+
addEventListener("turbo:before-fetch-request", event => {
|
36
|
+
if (window._overlasticAnchor) return
|
37
|
+
|
38
|
+
const frame = event.target.closest("turbo-frame[id^=overlay]")
|
39
|
+
|
40
|
+
if (frame) {
|
41
|
+
const target = frame.dataset.overlayTarget
|
42
|
+
const initiator = frame.dataset?.overlayInitiator
|
43
|
+
const type = frame.dataset?.overlayType
|
44
|
+
const args = frame.dataset?.overlayArgs
|
45
|
+
|
46
|
+
event.detail.fetchOptions.headers["Overlay-Target"] = target
|
47
|
+
|
48
|
+
if (initiator) {
|
49
|
+
event.detail.fetchOptions.headers["Overlay-Initiator"] = initiator
|
50
|
+
}
|
51
|
+
|
52
|
+
if (type) {
|
53
|
+
event.detail.fetchOptions.headers["Overlay-Type"] = type
|
54
|
+
}
|
55
|
+
|
56
|
+
if (args) {
|
57
|
+
event.detail.fetchOptions.headers["Overlay-Args"] = args
|
58
|
+
}
|
59
|
+
}
|
60
|
+
})
|
61
|
+
|
62
|
+
// Handle frame-to-visit promotions when the server asks for it
|
63
|
+
addEventListener("turbo:before-fetch-response", async event => {
|
64
|
+
const fetchResponse = event.detail.fetchResponse
|
65
|
+
const visit = fetchResponse.response.headers.get("Overlay-Visit")
|
66
|
+
|
67
|
+
if (!visit) return
|
68
|
+
|
69
|
+
const responseHTML = await fetchResponse.responseHTML
|
70
|
+
const { redirected, statusCode } = fetchResponse
|
71
|
+
|
72
|
+
return Turbo.session.visit(visit, { shouldCacheSnapshot: false, response: { redirected, statusCode, responseHTML } })
|
73
|
+
})
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<% title ||= "" %>
|
2
2
|
|
3
|
-
<%=
|
3
|
+
<%= overlastic_tag do %>
|
4
4
|
<overlastic-dialog style="height:100vh;background-color:rgba(107, 114, 128, 0.5);justify-content:center;align-items:center;width: 100vw;display:flex;z-index:50;left:0px;top:0px;position:fixed;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229, 231, 235);">
|
5
5
|
<div style="width: 50%;justify-content:center;align-items:center;flex-direction:column;max-width:672px;height:662.398px;display:flex;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229, 231, 235);">
|
6
6
|
<div style="padding-top:32px;padding-bottom:32px;box-shadow:rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.1) 0px 2px 4px -2px;background-color:rgb(255, 255, 255);overflow:hidden;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229, 231, 235);">
|
@@ -23,6 +23,4 @@
|
|
23
23
|
</div>
|
24
24
|
</div>
|
25
25
|
</overlastic-dialog>
|
26
|
-
|
27
|
-
<%= turbo_frame_tag next_overlay_name, target: :_top %>
|
28
26
|
<% end %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%=
|
1
|
+
<%= overlastic_tag do %>
|
2
2
|
<overlastic-pane style="background-color:rgba(107, 114, 128, 0.5);justify-content:flex-end;width: 100vw;height:100vh;display:flex;z-index:40;left:0px;top:0px;position:fixed;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229, 231, 235);">
|
3
3
|
<div style="width: 66.6667%;align-items:flex-end;flex-direction:column;animation:0.2s ease 0s 1 normal both running modal;height:100%;display:flex;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229, 231, 235);">
|
4
4
|
<div style="box-shadow:rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.1) 0px 2px 4px -2px;padding-top:20px;padding-bottom:20px;background-color:rgb(249, 250, 251);border-top-left-radius:8px;border-bottom-left-radius:8px;overflow:hidden;width: 100%;height:100%;box-sizing:border-box;border-width:0px;border-style:solid;border-color:rgb(229, 231, 235);">
|
@@ -17,6 +17,4 @@
|
|
17
17
|
</div>
|
18
18
|
</div>
|
19
19
|
</overlastic-pane>
|
20
|
-
|
21
|
-
<%= turbo_frame_tag next_overlay_name, target: :_top %>
|
22
20
|
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%= turbo_stream.append_all "head" do %>
|
2
|
+
<%= javascript_tag nonce: true do %>
|
3
|
+
frame = document.querySelector("turbo-frame[id=<%= escape_javascript overlay %>]")
|
4
|
+
|
5
|
+
frame.dataset.overlayInitiator = "1"
|
6
|
+
frame.src = "<%= escape_javascript location %>"
|
7
|
+
|
8
|
+
document.currentScript.remove()
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<% title ||= "" %>
|
2
2
|
|
3
|
-
<%=
|
3
|
+
<%= overlastic_tag do %>
|
4
4
|
<overlastic-dialog class="fixed top-0 left-0 z-50 flex justify-center w-screen h-screen-safe items-center bg-gray-500 bg-opacity-50">
|
5
5
|
<div class="w-11/12 sm:w-5/6 lg:w-1/2 max-w-2xl h-[90vh] flex flex-col justify-center items-center">
|
6
6
|
<div class="py-4 sm:py-8 bg-white shadow-md overflow-hidden">
|
@@ -23,6 +23,4 @@
|
|
23
23
|
</div>
|
24
24
|
</div>
|
25
25
|
</overlastic-dialog>
|
26
|
-
|
27
|
-
<%= turbo_frame_tag next_overlay_name, target: :_top %>
|
28
26
|
<% end %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%=
|
1
|
+
<%= overlastic_tag do %>
|
2
2
|
<overlastic-pane class="fixed top-0 left-0 z-40 flex justify-end w-screen h-screen bg-gray-500 bg-opacity-50">
|
3
3
|
<div class="w-full sm:w-5/6 lg:w-8/12 h-full flex flex-col items-end animate-modal">
|
4
4
|
<div id="split-container" class="py-5 bg-gray-50 rounded-l-lg shadow-md overflow-hidden w-full h-full">
|
@@ -17,6 +17,4 @@
|
|
17
17
|
</div>
|
18
18
|
</div>
|
19
19
|
</overlastic-pane>
|
20
|
-
|
21
|
-
<%= turbo_frame_tag next_overlay_name, target: :_top %>
|
22
20
|
<% end %>
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Overlastic
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :overlay_types, :default_overlay, :default_action
|
3
|
+
attr_accessor :overlay_types, :default_overlay, :default_action, :default_target
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
self.overlay_types = %i[dialog pane]
|
7
7
|
self.default_overlay = :dialog
|
8
8
|
self.default_action = :stack
|
9
|
+
self.default_target = :_top
|
9
10
|
end
|
10
11
|
|
11
12
|
def overlay_types=(types)
|
data/lib/overlastic/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: overlastic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Zamuner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-09-
|
11
|
+
date: 2022-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- app/javascript/overlastic/paneElement.js
|
74
74
|
- app/views/overlastic/inline/_dialog.html.erb
|
75
75
|
- app/views/overlastic/inline/_pane.html.erb
|
76
|
+
- app/views/overlastic/streams/redirect.turbo_stream.erb
|
76
77
|
- app/views/overlastic/tailwind/_dialog.html.erb
|
77
78
|
- app/views/overlastic/tailwind/_pane.html.erb
|
78
79
|
- lib/generators/overlastic/views/USAGE
|