katalyst-kpop 3.0.0.beta.5 → 3.0.0.beta.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6705e2c321b44b6722f8576883f3123eb8c057bd284cd8a380a9238245ae3328
4
- data.tar.gz: dd06a1336ad24a2ce7ac75df111652e8ebb17990ede11d8ca52012bda03d9438
3
+ metadata.gz: ea8b93a5914923b3ba6db7318e0887f3851bfc5774ae6e6790b543900da8d579
4
+ data.tar.gz: 336b3aeb96fcd5cc8293365fc2fc45609ec9334167048a93a7ac3d254ea82e36
5
5
  SHA512:
6
- metadata.gz: 7200aa276b9b0c23894fb3872c6633926ff30e1be63fbb33e5ad56d158c1d5305ae204e8ba8f09b153305191758793c5f658155ef5e7d65f24282e6fb6d92159
7
- data.tar.gz: 23cdd59c369995641e41d8b9adc65169f3bd13d845766c43734f45d2f3afd2f6d16bbf2c08a732b9f8c1df9b611af3ca27671ae85cf9d3a0bb0aab986b98ecbb
6
+ metadata.gz: bc928df7baf831a99ca7ef267270cebfae10170c18e91b99863ed830ab330c05807bce81f1a9b82384db4450fb8039c18dfb1cb6929f0c2475e026b6a9a650e7
7
+ data.tar.gz: ed9d5a3ab73686931a9494107680b048a5ab316d5e47f4afc315c203d5995505263f26c65a5e6abf62065e50c9d656c83795302d9975dd81c24f3bd91b9e2c83
@@ -158,6 +158,7 @@ class Kpop__FrameController extends Controller {
158
158
  this.debug("connect", this.element.src);
159
159
 
160
160
  this.element.kpop = this;
161
+ installNavigationInterception(this.element);
161
162
 
162
163
  // restoration visit
163
164
  if (this.element.src && this.element.complete) {
@@ -230,6 +231,20 @@ class Kpop__FrameController extends Controller {
230
231
  this.modal?.popstate(this, event);
231
232
  }
232
233
 
234
+ navigateFrame(element, location) {
235
+ this.debug("navigate-frame", this.element.src, location);
236
+
237
+ // Ensure that turbo doesn't cache the frame in a loading state by cancelling
238
+ // the current request (if any) by clearing the src.
239
+ // Known issue: this won't work if the frame was previously rendering a useful src.
240
+ if (this.element.hasAttribute("busy")) {
241
+ this.element.src = "";
242
+ }
243
+
244
+ // Delay turbo's navigateFrame until next tick to let the src change settle.
245
+ return Promise.resolve();
246
+ }
247
+
233
248
  beforeFrameRender(event) {
234
249
  this.debug("before-frame-render", event.detail.newFrame.baseURI);
235
250
 
@@ -328,6 +343,31 @@ class Kpop__FrameController extends Controller {
328
343
  }
329
344
  }
330
345
 
346
+ /**
347
+ * Monkey patch for Turbo#FrameController.
348
+ *
349
+ * Intercept calls to navigateFrame(element, location) and ensures that src is
350
+ * cleared if the frame is busy so that we don't restore an in-progress src on
351
+ * restoration visits.
352
+ *
353
+ * See Turbo issue: https://github.com/hotwired/turbo/issues/1055
354
+ *
355
+ * @param frameElement turbo-frame element
356
+ */
357
+ function installNavigationInterception(frameElement) {
358
+ if (frameElement.delegate._navigateFrame === undefined) {
359
+ frameElement.delegate._navigateFrame = frameElement.delegate.navigateFrame;
360
+ frameElement.delegate.navigateFrame = async (element, location) => {
361
+ await frameElement.kpop?.navigateFrame(element, location);
362
+ return frameElement.delegate._navigateFrame.call(
363
+ frameElement.delegate,
364
+ element,
365
+ location
366
+ );
367
+ };
368
+ }
369
+ }
370
+
331
371
  class Kpop__ModalController extends Controller {
332
372
  static values = {
333
373
  fallback_location: String,
@@ -158,6 +158,7 @@ class Kpop__FrameController extends Controller {
158
158
  this.debug("connect", this.element.src);
159
159
 
160
160
  this.element.kpop = this;
161
+ installNavigationInterception(this.element);
161
162
 
162
163
  // restoration visit
163
164
  if (this.element.src && this.element.complete) {
@@ -230,6 +231,20 @@ class Kpop__FrameController extends Controller {
230
231
  this.modal?.popstate(this, event);
231
232
  }
232
233
 
234
+ navigateFrame(element, location) {
235
+ this.debug("navigate-frame", this.element.src, location);
236
+
237
+ // Ensure that turbo doesn't cache the frame in a loading state by cancelling
238
+ // the current request (if any) by clearing the src.
239
+ // Known issue: this won't work if the frame was previously rendering a useful src.
240
+ if (this.element.hasAttribute("busy")) {
241
+ this.element.src = "";
242
+ }
243
+
244
+ // Delay turbo's navigateFrame until next tick to let the src change settle.
245
+ return Promise.resolve();
246
+ }
247
+
233
248
  beforeFrameRender(event) {
234
249
  this.debug("before-frame-render", event.detail.newFrame.baseURI);
235
250
 
@@ -328,6 +343,31 @@ class Kpop__FrameController extends Controller {
328
343
  }
329
344
  }
330
345
 
346
+ /**
347
+ * Monkey patch for Turbo#FrameController.
348
+ *
349
+ * Intercept calls to navigateFrame(element, location) and ensures that src is
350
+ * cleared if the frame is busy so that we don't restore an in-progress src on
351
+ * restoration visits.
352
+ *
353
+ * See Turbo issue: https://github.com/hotwired/turbo/issues/1055
354
+ *
355
+ * @param frameElement turbo-frame element
356
+ */
357
+ function installNavigationInterception(frameElement) {
358
+ if (frameElement.delegate._navigateFrame === undefined) {
359
+ frameElement.delegate._navigateFrame = frameElement.delegate.navigateFrame;
360
+ frameElement.delegate.navigateFrame = async (element, location) => {
361
+ await frameElement.kpop?.navigateFrame(element, location);
362
+ return frameElement.delegate._navigateFrame.call(
363
+ frameElement.delegate,
364
+ element,
365
+ location
366
+ );
367
+ };
368
+ }
369
+ }
370
+
331
371
  class Kpop__ModalController extends Controller {
332
372
  static values = {
333
373
  fallback_location: String,
@@ -1,2 +1,2 @@
1
- import{Controller as e}from"@hotwired/stimulus";import{Turbo as t}from"@hotwired/turbo-rails";class s{constructor(e){this.id=e}async open(){this.debug("open")}async dismiss(){this.debug("dismiss")}beforeVisit(e,t){this.debug("before-visit",t.detail.url)}popstate(e,t){this.debug("popstate",t.state)}async pop(e,t){this.debug("pop");const s=new Promise((t=>{window.addEventListener(e,(()=>{t()}),{once:!0})}));return t(),s}get frameElement(){return document.getElementById(this.id)}get modalElement(){return this.frameElement?.querySelector("[data-controller*='kpop--modal']")}get currentLocationValue(){return this.modalElement?.dataset["kpop-ModalCurrentLocationValue"]||"/"}get fallbackLocationValue(){return this.modalElement?.dataset["kpop-ModalFallbackLocationValue"]||"/"}get isCurrentLocation(){return window.history.state?.turbo&&t.session.location.href===this.src}debug(e,...t){}}class i extends s{constructor(e,t=null){super(e),t&&(this.src=t)}async dismiss(){if(await super.dismiss(),this.visitStarted)this.debug("skipping dismiss, visit started");else{if(this.isCurrentLocation)return this.pop("turbo:load",(()=>{this.debug("turbo-visit",this.fallbackLocationValue),t.visit(this.fallbackLocationValue)}));this.debug("skipping dismiss, not current location")}}beforeVisit(e,t){super.beforeVisit(e,t),this.visitStarted=!0,e.scrimOutlet.hide({animate:!1})}get src(){return new URL(this.currentLocationValue.toString(),document.baseURI).toString()}}class n extends s{constructor(e,t){super(e),this.src=t}async dismiss(){await super.dismiss(),this.isCurrentLocation?await this.pop("turbo:load",(()=>window.history.back())):this.debug("skipping dismiss, not current location")}beforeVisit(e,s){super.beforeVisit(e,s),s.preventDefault(),e.dismiss({animate:!1}).then((()=>{t.visit(s.detail.url),this.debug("before-visit-end")}))}popstate(e,t){super.popstate(e,t),e.scrimOutlet.hide({animate:!1})}}class a extends e{static outlets=["scrim"];static targets=["modal"];static values={open:Boolean};connect(){if(this.debug("connect",this.element.src),this.element.kpop=this,this.element.src&&this.element.complete)this.debug("new frame modal",this.element.src),this.open(new n(this.element.id,this.element.src),{animate:!1});else{this.element.querySelector("[data-controller*='kpop--modal']")&&(this.debug("new content modal",window.location.pathname),this.open(new i(this.element.id),{animate:!1}))}}disconnect(){this.debug("disconnect"),delete this.element.kpop,delete this.modal}scrimOutletConnected(e){this.debug("scrim-connected"),this.scrimConnected=!0,this.openValue?e.show({animate:!1}):e.hide({animate:!1})}openValueChanged(e){this.debug("open-changed",e),this.element.parentElement.style.display=e?"flex":"none"}async open(e,{animate:t=!0}={}){return this.isOpen?(this.debug("skip open as already open"),this.modal||=e,!1):this.opening||=this.#e((()=>this.#t(e,{animate:t})))}async dismiss({animate:e=!0,reason:t=""}={}){return this.isOpen?this.dismissing||=this.#e((()=>this.#s({animate:e,reason:t}))):(this.debug("skip dismiss as already closed"),!1)}popstate(e){this.modal?.popstate(this,e)}beforeFrameRender(e){this.debug("before-frame-render",e.detail.newFrame.baseURI),e.preventDefault(),this.dismiss({animate:!0,reason:"before-frame-render"}).then((()=>{this.debug("resume-frame-render",e.detail.newFrame.baseURI),e.detail.resume()}))}beforeStreamRender(e){this.debug("before-stream-render",e.detail);const t=e.detail.render;e.detail.render=e=>{(this.dismissing||Promise.resolve()).then((()=>{this.debug("stream-render",e),t(e)}))}}beforeVisit(e){this.debug("before-visit",e.detail.url),e.detail.url!==this.element.src&&this.isOpen&&this.modal.beforeVisit(this,e)}frameLoad(e){return this.debug("frame-load"),this.open(new n(this.element.id,this.element.src),{animate:!0})}get isOpen(){return this.openValue&&!this.dismissing}async#t(e,{animate:t=!0}={}){this.debug("open-start",{animate:t});const s=this.scrimConnected&&this.scrimOutlet;this.modal=e,this.openValue=!0,await e.open({animate:t}),await(s?.show({animate:t})),delete this.opening,this.debug("open-end")}async#s({animate:e=!0,reason:t=""}={}){this.debug("dismiss-start",{animate:e,reason:t}),this.element.isConnected?(this.modal||console.warn("modal missing on dismiss"),await this.scrimOutlet.hide({animate:e}),await(this.modal?.dismiss()),this.openValue=!1,this.modal=null,delete this.dismissing,this.debug("dismiss-end")):this.debug("skip dismiss, element detached")}async#e(e){return new Promise(window.requestAnimationFrame).then(e)}debug(e,...t){}}class o extends e{static values={open:Boolean,captive:Boolean,zIndex:Number};connect(){this.defaultZIndexValue=this.zIndexValue,this.defaultCaptiveValue=this.captiveValue,this.element.scrim=this}disconnect(){delete this.element.scrim}async show({captive:e=this.defaultCaptiveValue,zIndex:t=this.defaultZIndexValue,top:s=window.scrollY,animate:i=!0}={}){this.openValue&&await this.hide({animate:i}),this.openValue=!0,this.dispatch("show",{bubbles:!0}),this.#i(e,t,s),i&&(this.element.dataset.showAnimating="",await new Promise((e=>{this.element.addEventListener("animationend",(()=>e()),{once:!0})})),delete this.element.dataset.showAnimating)}async hide({animate:e=!0}={}){this.openValue&&!this.element.dataset.hideAnimating&&(this.dispatch("hide",{bubbles:!0}),e&&(this.element.dataset.hideAnimating="",await new Promise((e=>{this.element.addEventListener("animationend",(()=>e()),{once:!0})})),delete this.element.dataset.hideAnimating),this.#n(),this.openValue=!1)}dismiss(e){this.captiveValue||this.dispatch("dismiss",{bubbles:!0})}escape(e){"Escape"!==e.key||this.captiveValue||e.defaultPrevented||this.dispatch("dismiss",{bubbles:!0})}#i(e,t,s){this.captiveValue=e,this.zIndexValue=t,this.scrollY=s,this.previousPosition=document.body.style.position,this.previousTop=document.body.style.top,this.element.style.zIndex=this.zIndexValue,document.body.style.top=`-${s}px`,document.body.style.position="fixed"}#n(){this.captiveValue=this.defaultCaptiveValue,this.zIndexValue=this.defaultZIndexValue,r(this.element,"z-index",null),r(document.body,"position",null),r(document.body,"top",null),window.scrollTo({left:0,top:this.scrollY,behavior:"instant"}),delete this.scrollY,delete this.previousPosition,delete this.previousTop}}function r(e,t,s){s?e.style.setProperty(t,s):e.style.removeProperty(t)}class d extends s{constructor(e,t){super(e),this.action=t}async open(){await super.open(),window.history.pushState({kpop:!0,id:this.id},"",window.location)}async dismiss(){await super.dismiss(),this.isCurrentLocation&&await this.pop("popstate",(()=>window.history.back())),this.frameElement.innerHTML=""}beforeVisit(e,s){super.beforeVisit(e,s),s.preventDefault(),e.dismiss({animate:!1}).then((()=>{t.visit(s.detail.url),this.debug("before-visit-end")}))}popstate(e,t){super.popstate(e,t),e.dismiss({animate:!0,reason:"popstate"})}get isCurrentLocation(){return window.history.state?.kpop&&window.history.state?.id===this.id}}class l{constructor(e,t){this.frame=e,this.action=t}render(){this.frame.src="",this.frame.innerHTML="",this.frame.append(this.action.templateContent)}}function h(e){return e.targetElements[0]?.kpop}t.StreamActions.kpop_open=function(){const e=!h(this).openValue;h(this)?.dismiss({animate:e,reason:"before-turbo-stream"}).then((()=>{new l(this.targetElements[0],this).render(),h(this)?.open(new d(this.target,this),{animate:e})}))},t.StreamActions.kpop_dismiss=function(){h(this)?.dismiss({reason:"turbo_stream.kpop.dismiss"})},t.StreamActions.kpop_redirect_to=function(){if(this.dataset.turboFrame===this.target){const e=document.createElement("A");e.setAttribute("data-turbo-action","replace"),this.targetElements[0].delegate.navigateFrame(e,this.getAttribute("href"))}else t.visit(this.getAttribute("href"),{action:this.dataset.turboAction})};const m=[{identifier:"kpop--frame",controllerConstructor:a},{identifier:"kpop--modal",controllerConstructor:class extends e{static values={fallback_location:String,layout:String};connect(){this.debug("connect"),this.layoutValue&&document.querySelector("#kpop").classList.toggle(this.layoutValue,!0)}disconnect(){this.debug("disconnect"),this.layoutValue&&document.querySelector("#kpop").classList.toggle(this.layoutValue,!1)}debug(e,...t){}}},{identifier:"scrim",controllerConstructor:o}];export{m as default};
1
+ import{Controller as e}from"@hotwired/stimulus";import{Turbo as t}from"@hotwired/turbo-rails";class i{constructor(e){this.id=e}async open(){this.debug("open")}async dismiss(){this.debug("dismiss")}beforeVisit(e,t){this.debug("before-visit",t.detail.url)}popstate(e,t){this.debug("popstate",t.state)}async pop(e,t){this.debug("pop");const i=new Promise((t=>{window.addEventListener(e,(()=>{t()}),{once:!0})}));return t(),i}get frameElement(){return document.getElementById(this.id)}get modalElement(){return this.frameElement?.querySelector("[data-controller*='kpop--modal']")}get currentLocationValue(){return this.modalElement?.dataset["kpop-ModalCurrentLocationValue"]||"/"}get fallbackLocationValue(){return this.modalElement?.dataset["kpop-ModalFallbackLocationValue"]||"/"}get isCurrentLocation(){return window.history.state?.turbo&&t.session.location.href===this.src}debug(e,...t){}}class s extends i{constructor(e,t=null){super(e),t&&(this.src=t)}async dismiss(){if(await super.dismiss(),this.visitStarted)this.debug("skipping dismiss, visit started");else{if(this.isCurrentLocation)return this.pop("turbo:load",(()=>{this.debug("turbo-visit",this.fallbackLocationValue),t.visit(this.fallbackLocationValue)}));this.debug("skipping dismiss, not current location")}}beforeVisit(e,t){super.beforeVisit(e,t),this.visitStarted=!0,e.scrimOutlet.hide({animate:!1})}get src(){return new URL(this.currentLocationValue.toString(),document.baseURI).toString()}}class a extends i{constructor(e,t){super(e),this.src=t}async dismiss(){await super.dismiss(),this.isCurrentLocation?await this.pop("turbo:load",(()=>window.history.back())):this.debug("skipping dismiss, not current location")}beforeVisit(e,i){super.beforeVisit(e,i),i.preventDefault(),e.dismiss({animate:!1}).then((()=>{t.visit(i.detail.url),this.debug("before-visit-end")}))}popstate(e,t){super.popstate(e,t),e.scrimOutlet.hide({animate:!1})}}class n extends e{static outlets=["scrim"];static targets=["modal"];static values={open:Boolean};connect(){var e;if(this.debug("connect",this.element.src),this.element.kpop=this,void 0===(e=this.element).delegate._navigateFrame&&(e.delegate._navigateFrame=e.delegate.navigateFrame,e.delegate.navigateFrame=async(t,i)=>(await(e.kpop?.navigateFrame(t,i)),e.delegate._navigateFrame.call(e.delegate,t,i))),this.element.src&&this.element.complete)this.debug("new frame modal",this.element.src),this.open(new a(this.element.id,this.element.src),{animate:!1});else{this.element.querySelector("[data-controller*='kpop--modal']")&&(this.debug("new content modal",window.location.pathname),this.open(new s(this.element.id),{animate:!1}))}}disconnect(){this.debug("disconnect"),delete this.element.kpop,delete this.modal}scrimOutletConnected(e){this.debug("scrim-connected"),this.scrimConnected=!0,this.openValue?e.show({animate:!1}):e.hide({animate:!1})}openValueChanged(e){this.debug("open-changed",e),this.element.parentElement.style.display=e?"flex":"none"}async open(e,{animate:t=!0}={}){return this.isOpen?(this.debug("skip open as already open"),this.modal||=e,!1):this.opening||=this.#e((()=>this.#t(e,{animate:t})))}async dismiss({animate:e=!0,reason:t=""}={}){return this.isOpen?this.dismissing||=this.#e((()=>this.#i({animate:e,reason:t}))):(this.debug("skip dismiss as already closed"),!1)}popstate(e){this.modal?.popstate(this,e)}navigateFrame(e,t){return this.debug("navigate-frame",this.element.src,t),this.element.hasAttribute("busy")&&(this.element.src=""),Promise.resolve()}beforeFrameRender(e){this.debug("before-frame-render",e.detail.newFrame.baseURI),e.preventDefault(),this.dismiss({animate:!0,reason:"before-frame-render"}).then((()=>{this.debug("resume-frame-render",e.detail.newFrame.baseURI),e.detail.resume()}))}beforeStreamRender(e){this.debug("before-stream-render",e.detail);const t=e.detail.render;e.detail.render=e=>{(this.dismissing||Promise.resolve()).then((()=>{this.debug("stream-render",e),t(e)}))}}beforeVisit(e){this.debug("before-visit",e.detail.url),e.detail.url!==this.element.src&&this.isOpen&&this.modal.beforeVisit(this,e)}frameLoad(e){return this.debug("frame-load"),this.open(new a(this.element.id,this.element.src),{animate:!0})}get isOpen(){return this.openValue&&!this.dismissing}async#t(e,{animate:t=!0}={}){this.debug("open-start",{animate:t});const i=this.scrimConnected&&this.scrimOutlet;this.modal=e,this.openValue=!0,await e.open({animate:t}),await(i?.show({animate:t})),delete this.opening,this.debug("open-end")}async#i({animate:e=!0,reason:t=""}={}){this.debug("dismiss-start",{animate:e,reason:t}),this.element.isConnected?(this.modal||console.warn("modal missing on dismiss"),await this.scrimOutlet.hide({animate:e}),await(this.modal?.dismiss()),this.openValue=!1,this.modal=null,delete this.dismissing,this.debug("dismiss-end")):this.debug("skip dismiss, element detached")}async#e(e){return new Promise(window.requestAnimationFrame).then(e)}debug(e,...t){}}class o extends e{static values={open:Boolean,captive:Boolean,zIndex:Number};connect(){this.defaultZIndexValue=this.zIndexValue,this.defaultCaptiveValue=this.captiveValue,this.element.scrim=this}disconnect(){delete this.element.scrim}async show({captive:e=this.defaultCaptiveValue,zIndex:t=this.defaultZIndexValue,top:i=window.scrollY,animate:s=!0}={}){this.openValue&&await this.hide({animate:s}),this.openValue=!0,this.dispatch("show",{bubbles:!0}),this.#s(e,t,i),s&&(this.element.dataset.showAnimating="",await new Promise((e=>{this.element.addEventListener("animationend",(()=>e()),{once:!0})})),delete this.element.dataset.showAnimating)}async hide({animate:e=!0}={}){this.openValue&&!this.element.dataset.hideAnimating&&(this.dispatch("hide",{bubbles:!0}),e&&(this.element.dataset.hideAnimating="",await new Promise((e=>{this.element.addEventListener("animationend",(()=>e()),{once:!0})})),delete this.element.dataset.hideAnimating),this.#a(),this.openValue=!1)}dismiss(e){this.captiveValue||this.dispatch("dismiss",{bubbles:!0})}escape(e){"Escape"!==e.key||this.captiveValue||e.defaultPrevented||this.dispatch("dismiss",{bubbles:!0})}#s(e,t,i){this.captiveValue=e,this.zIndexValue=t,this.scrollY=i,this.previousPosition=document.body.style.position,this.previousTop=document.body.style.top,this.element.style.zIndex=this.zIndexValue,document.body.style.top=`-${i}px`,document.body.style.position="fixed"}#a(){this.captiveValue=this.defaultCaptiveValue,this.zIndexValue=this.defaultZIndexValue,r(this.element,"z-index",null),r(document.body,"position",null),r(document.body,"top",null),window.scrollTo({left:0,top:this.scrollY,behavior:"instant"}),delete this.scrollY,delete this.previousPosition,delete this.previousTop}}function r(e,t,i){i?e.style.setProperty(t,i):e.style.removeProperty(t)}class d extends i{constructor(e,t){super(e),this.action=t}async open(){await super.open(),window.history.pushState({kpop:!0,id:this.id},"",window.location)}async dismiss(){await super.dismiss(),this.isCurrentLocation&&await this.pop("popstate",(()=>window.history.back())),this.frameElement.innerHTML=""}beforeVisit(e,i){super.beforeVisit(e,i),i.preventDefault(),e.dismiss({animate:!1}).then((()=>{t.visit(i.detail.url),this.debug("before-visit-end")}))}popstate(e,t){super.popstate(e,t),e.dismiss({animate:!0,reason:"popstate"})}get isCurrentLocation(){return window.history.state?.kpop&&window.history.state?.id===this.id}}class l{constructor(e,t){this.frame=e,this.action=t}render(){this.frame.src="",this.frame.innerHTML="",this.frame.append(this.action.templateContent)}}function h(e){return e.targetElements[0]?.kpop}t.StreamActions.kpop_open=function(){const e=!h(this).openValue;h(this)?.dismiss({animate:e,reason:"before-turbo-stream"}).then((()=>{new l(this.targetElements[0],this).render(),h(this)?.open(new d(this.target,this),{animate:e})}))},t.StreamActions.kpop_dismiss=function(){h(this)?.dismiss({reason:"turbo_stream.kpop.dismiss"})},t.StreamActions.kpop_redirect_to=function(){if(this.dataset.turboFrame===this.target){const e=document.createElement("A");e.setAttribute("data-turbo-action","replace"),this.targetElements[0].delegate.navigateFrame(e,this.getAttribute("href"))}else t.visit(this.getAttribute("href"),{action:this.dataset.turboAction})};const m=[{identifier:"kpop--frame",controllerConstructor:n},{identifier:"kpop--modal",controllerConstructor:class extends e{static values={fallback_location:String,layout:String};connect(){this.debug("connect"),this.layoutValue&&document.querySelector("#kpop").classList.toggle(this.layoutValue,!0)}disconnect(){this.debug("disconnect"),this.layoutValue&&document.querySelector("#kpop").classList.toggle(this.layoutValue,!1)}debug(e,...t){}}},{identifier:"scrim",controllerConstructor:o}];export{m as default};
2
2
  //# sourceMappingURL=kpop.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"kpop.min.js","sources":["../../../javascript/kpop/modals/modal.js","../../../javascript/kpop/modals/content_modal.js","../../../javascript/kpop/modals/frame_modal.js","../../../javascript/kpop/controllers/frame_controller.js","../../../javascript/kpop/controllers/scrim_controller.js","../../../javascript/kpop/modals/stream_modal.js","../../../javascript/kpop/utils/stream_renderer.js","../../../javascript/kpop/turbo_actions.js","../../../javascript/kpop/application.js","../../../javascript/kpop/controllers/modal_controller.js"],"sourcesContent":["import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport DEBUG from \"../debug\";\n\nexport class Modal {\n constructor(id) {\n this.id = id;\n }\n\n async open() {\n this.debug(\"open\");\n }\n\n async dismiss() {\n this.debug(`dismiss`);\n }\n\n beforeVisit(frame, e) {\n this.debug(`before-visit`, e.detail.url);\n }\n\n popstate(frame, e) {\n this.debug(`popstate`, e.state);\n }\n\n async pop(event, callback) {\n this.debug(`pop`);\n\n const promise = new Promise((resolve) => {\n window.addEventListener(\n event,\n () => {\n resolve();\n },\n { once: true }\n );\n });\n\n callback();\n\n return promise;\n }\n\n get frameElement() {\n return document.getElementById(this.id);\n }\n\n get modalElement() {\n return this.frameElement?.querySelector(\"[data-controller*='kpop--modal']\");\n }\n\n get currentLocationValue() {\n return this.modalElement?.dataset[\"kpop-ModalCurrentLocationValue\"] || \"/\";\n }\n\n get fallbackLocationValue() {\n return this.modalElement?.dataset[\"kpop-ModalFallbackLocationValue\"] || \"/\";\n }\n\n get isCurrentLocation() {\n return (\n window.history.state?.turbo && Turbo.session.location.href === this.src\n );\n }\n\n debug(event, ...args) {\n if (DEBUG) console.debug(`${this.constructor.name}:${event}`, ...args);\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport { Modal } from \"./modal\";\n\nexport class ContentModal extends Modal {\n constructor(id, src = null) {\n super(id);\n\n if (src) this.src = src;\n }\n\n async dismiss() {\n await super.dismiss();\n\n if (this.visitStarted) {\n this.debug(\"skipping dismiss, visit started\");\n return;\n }\n if (!this.isCurrentLocation) {\n this.debug(\"skipping dismiss, not current location\");\n return;\n }\n\n return this.pop(\"turbo:load\", () => {\n this.debug(\"turbo-visit\", this.fallbackLocationValue);\n Turbo.visit(this.fallbackLocationValue);\n });\n\n // no specific close action required, this is turbo's responsibility\n }\n\n beforeVisit(frame, e) {\n super.beforeVisit(frame, e);\n\n this.visitStarted = true;\n\n frame.scrimOutlet.hide({ animate: false });\n }\n\n get src() {\n return new URL(\n this.currentLocationValue.toString(),\n document.baseURI\n ).toString();\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport { Modal } from \"./modal\";\n\nexport class FrameModal extends Modal {\n constructor(id, src) {\n super(id);\n this.src = src;\n }\n\n async dismiss() {\n await super.dismiss();\n\n if (!this.isCurrentLocation) {\n this.debug(\"skipping dismiss, not current location\");\n } else {\n await this.pop(\"turbo:load\", () => window.history.back());\n }\n\n // no specific close action required, this is turbo's responsibility\n }\n\n beforeVisit(frame, e) {\n super.beforeVisit(frame, e);\n\n e.preventDefault();\n\n frame.dismiss({ animate: false }).then(() => {\n Turbo.visit(e.detail.url);\n\n this.debug(\"before-visit-end\");\n });\n }\n\n popstate(frame, e) {\n super.popstate(frame, e);\n\n // Turbo will restore modal state, but we need to reset the scrim\n frame.scrimOutlet.hide({ animate: false });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport DEBUG from \"../debug\";\nimport { ContentModal } from \"../modals/content_modal\";\nimport { FrameModal } from \"../modals/frame_modal\";\n\nexport default class Kpop__FrameController extends Controller {\n static outlets = [\"scrim\"];\n static targets = [\"modal\"];\n static values = {\n open: Boolean,\n };\n\n connect() {\n this.debug(\"connect\", this.element.src);\n\n this.element.kpop = this;\n\n // restoration visit\n if (this.element.src && this.element.complete) {\n this.debug(\"new frame modal\", this.element.src);\n this.open(new FrameModal(this.element.id, this.element.src), {\n animate: false,\n });\n } else {\n const element = this.element.querySelector(\n \"[data-controller*='kpop--modal']\"\n );\n if (element) {\n this.debug(\"new content modal\", window.location.pathname);\n this.open(new ContentModal(this.element.id), { animate: false });\n }\n }\n }\n\n disconnect() {\n this.debug(\"disconnect\");\n\n delete this.element.kpop;\n delete this.modal;\n }\n\n scrimOutletConnected(scrim) {\n this.debug(\"scrim-connected\");\n\n this.scrimConnected = true;\n\n if (this.openValue) {\n scrim.show({ animate: false });\n } else {\n scrim.hide({ animate: false });\n }\n }\n\n openValueChanged(open) {\n this.debug(\"open-changed\", open);\n\n this.element.parentElement.style.display = open ? \"flex\" : \"none\";\n }\n\n async open(modal, { animate = true } = {}) {\n if (this.isOpen) {\n this.debug(\"skip open as already open\");\n this.modal ||= modal;\n return false;\n }\n\n return (this.opening ||= this.#nextFrame(() =>\n this.#open(modal, { animate })\n ));\n }\n\n async dismiss({ animate = true, reason = \"\" } = {}) {\n if (!this.isOpen) {\n this.debug(\"skip dismiss as already closed\");\n return false;\n }\n\n return (this.dismissing ||= this.#nextFrame(() =>\n this.#dismiss({ animate, reason })\n ));\n }\n\n // EVENTS\n\n popstate(event) {\n this.modal?.popstate(this, event);\n }\n\n beforeFrameRender(event) {\n this.debug(\"before-frame-render\", event.detail.newFrame.baseURI);\n\n event.preventDefault();\n\n this.dismiss({ animate: true, reason: \"before-frame-render\" }).then(() => {\n this.debug(\"resume-frame-render\", event.detail.newFrame.baseURI);\n event.detail.resume();\n });\n }\n\n beforeStreamRender(event) {\n this.debug(\"before-stream-render\", event.detail);\n\n const resume = event.detail.render;\n\n // Defer rendering until dismiss is complete.\n // Dismiss may change history so we need to wait for it to complete to avoid\n // losing DOM changes on restoration visits.\n event.detail.render = (stream) => {\n (this.dismissing || Promise.resolve()).then(() => {\n this.debug(\"stream-render\", stream);\n resume(stream);\n });\n };\n }\n\n beforeVisit(e) {\n this.debug(\"before-visit\", e.detail.url);\n\n // ignore visits to the current frame, these fire when the frame navigates\n if (e.detail.url === this.element.src) return;\n\n // ignore unless we're open\n if (!this.isOpen) return;\n\n this.modal.beforeVisit(this, e);\n }\n\n frameLoad(event) {\n this.debug(\"frame-load\");\n\n return this.open(new FrameModal(this.element.id, this.element.src), {\n animate: true,\n });\n }\n\n get isOpen() {\n return this.openValue && !this.dismissing;\n }\n\n async #open(modal, { animate = true } = {}) {\n this.debug(\"open-start\", { animate });\n\n const scrim = this.scrimConnected && this.scrimOutlet;\n\n this.modal = modal;\n this.openValue = true;\n\n await modal.open({ animate });\n await scrim?.show({ animate });\n\n delete this.opening;\n\n this.debug(\"open-end\");\n }\n\n async #dismiss({ animate = true, reason = \"\" } = {}) {\n this.debug(\"dismiss-start\", { animate, reason });\n\n // if this element is detached then we've experienced a turbo navigation\n if (!this.element.isConnected) {\n this.debug(\"skip dismiss, element detached\");\n return;\n }\n\n if (!this.modal) {\n console.warn(\"modal missing on dismiss\");\n if (DEBUG) debugger;\n }\n\n await this.scrimOutlet.hide({ animate });\n await this.modal?.dismiss();\n\n this.openValue = false;\n this.modal = null;\n delete this.dismissing;\n\n this.debug(\"dismiss-end\");\n }\n\n async #nextFrame(callback) {\n return new Promise(window.requestAnimationFrame).then(callback);\n }\n\n debug(event, ...args) {\n if (DEBUG) console.debug(`FrameController:${event}`, ...args);\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport DEBUG from \"../debug\";\n\n/**\n * Scrim controller wraps an element that creates a whole page layer.\n * It is intended to be used behind a modal or nav drawer.\n *\n * If the Scrim element receives a click event, it automatically triggers \"scrim:hide\".\n *\n * You can show and hide the scrim programmatically by calling show/hide on the controller, e.g. using an outlet.\n *\n * If you need to respond to the scrim showing or hiding you should subscribe to \"scrim:show\" and \"scrim:hide\".\n */\nexport default class ScrimController extends Controller {\n static values = {\n open: Boolean,\n captive: Boolean,\n zIndex: Number,\n };\n\n connect() {\n if (DEBUG) console.debug(\"scrim:connect\");\n\n this.defaultZIndexValue = this.zIndexValue;\n this.defaultCaptiveValue = this.captiveValue;\n\n this.element.scrim = this;\n }\n\n disconnect() {\n if (DEBUG) console.debug(\"scrim:disconnect\");\n\n delete this.element.scrim;\n }\n\n async show({\n captive = this.defaultCaptiveValue,\n zIndex = this.defaultZIndexValue,\n top = window.scrollY,\n animate = true,\n } = {}) {\n if (DEBUG) console.debug(\"scrim:before-show\");\n\n // hide the scrim before opening the new one if it's already open\n if (this.openValue) {\n await this.hide({ animate });\n }\n\n // update internal state\n this.openValue = true;\n\n // notify listeners of pending request\n this.dispatch(\"show\", { bubbles: true });\n\n if (DEBUG) console.debug(\"scrim:show-start\");\n\n // update state, perform style updates\n this.#show(captive, zIndex, top);\n\n if (animate) {\n // animate opening\n // this will trigger an animationEnd event via CSS that completes the open\n this.element.dataset.showAnimating = \"\";\n\n await new Promise((resolve) => {\n this.element.addEventListener(\"animationend\", () => resolve(), {\n once: true,\n });\n });\n\n delete this.element.dataset.showAnimating;\n }\n\n if (DEBUG) console.debug(\"scrim:show-end\");\n }\n\n async hide({ animate = true } = {}) {\n if (!this.openValue || this.element.dataset.hideAnimating) return;\n\n if (DEBUG) console.debug(\"scrim:before-hide\");\n\n // notify listeners of pending request\n this.dispatch(\"hide\", { bubbles: true });\n\n if (DEBUG) console.debug(\"scrim:hide-start\");\n\n if (animate) {\n // set animation state\n // this will trigger an animationEnd event via CSS that completes the hide\n this.element.dataset.hideAnimating = \"\";\n\n await new Promise((resolve) => {\n this.element.addEventListener(\"animationend\", () => resolve(), {\n once: true,\n });\n });\n\n delete this.element.dataset.hideAnimating;\n }\n\n this.#hide();\n\n this.openValue = false;\n\n if (DEBUG) console.debug(\"scrim:hide-end\");\n }\n\n dismiss(event) {\n if (DEBUG) console.debug(\"scrim:dismiss\");\n\n if (!this.captiveValue) this.dispatch(\"dismiss\", { bubbles: true });\n }\n\n escape(event) {\n if (\n event.key === \"Escape\" &&\n !this.captiveValue &&\n !event.defaultPrevented\n ) {\n this.dispatch(\"dismiss\", { bubbles: true });\n }\n }\n\n /**\n * Clips body to viewport size and sets the z-index\n */\n #show(captive, zIndex, top) {\n this.captiveValue = captive;\n this.zIndexValue = zIndex;\n this.scrollY = top;\n\n this.previousPosition = document.body.style.position;\n this.previousTop = document.body.style.top;\n\n this.element.style.zIndex = this.zIndexValue;\n document.body.style.top = `-${top}px`;\n document.body.style.position = \"fixed\";\n }\n\n /**\n * Unclips body from viewport size and unsets the z-index\n */\n #hide() {\n this.captiveValue = this.defaultCaptiveValue;\n this.zIndexValue = this.defaultZIndexValue;\n\n resetStyle(this.element, \"z-index\", null);\n resetStyle(document.body, \"position\", null);\n resetStyle(document.body, \"top\", null);\n\n window.scrollTo({ left: 0, top: this.scrollY, behavior: \"instant\" });\n\n delete this.scrollY;\n delete this.previousPosition;\n delete this.previousTop;\n }\n}\n\nfunction resetStyle(element, property, previousValue) {\n if (previousValue) {\n element.style.setProperty(property, previousValue);\n } else {\n element.style.removeProperty(property);\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport { Modal } from \"./modal\";\n\nexport class StreamModal extends Modal {\n constructor(id, action) {\n super(id);\n\n this.action = action;\n }\n\n async open() {\n await super.open();\n\n window.history.pushState({ kpop: true, id: this.id }, \"\", window.location);\n }\n\n async dismiss() {\n await super.dismiss();\n\n if (this.isCurrentLocation) {\n await this.pop(\"popstate\", () => window.history.back());\n }\n\n this.frameElement.innerHTML = \"\";\n }\n\n beforeVisit(frame, e) {\n super.beforeVisit(frame, e);\n\n e.preventDefault();\n\n frame.dismiss({ animate: false }).then(() => {\n Turbo.visit(e.detail.url);\n\n this.debug(\"before-visit-end\");\n });\n }\n\n popstate(frame, e) {\n super.popstate(frame, e);\n\n frame.dismiss({ animate: true, reason: \"popstate\" });\n }\n\n get isCurrentLocation() {\n return window.history.state?.kpop && window.history.state?.id === this.id;\n }\n}\n","import DEBUG from \"../debug\";\n\nexport class StreamRenderer {\n constructor(frame, action) {\n this.frame = frame;\n this.action = action;\n }\n\n render() {\n if (DEBUG) console.debug(\"stream-renderer:render\");\n this.frame.src = \"\";\n this.frame.innerHTML = \"\";\n this.frame.append(this.action.templateContent);\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport DEBUG from \"./debug\";\n\nimport { StreamModal } from \"./modals/stream_modal\";\nimport { StreamRenderer } from \"./utils/stream_renderer\";\n\nfunction kpop(action) {\n return action.targetElements[0]?.kpop;\n}\n\nTurbo.StreamActions.kpop_open = function () {\n const animate = !kpop(this).openValue;\n\n kpop(this)\n ?.dismiss({ animate, reason: \"before-turbo-stream\" })\n .then(() => {\n new StreamRenderer(this.targetElements[0], this).render();\n kpop(this)?.open(new StreamModal(this.target, this), { animate });\n });\n};\n\nTurbo.StreamActions.kpop_dismiss = function () {\n kpop(this)?.dismiss({ reason: \"turbo_stream.kpop.dismiss\" });\n};\n\nTurbo.StreamActions.kpop_redirect_to = function () {\n if (this.dataset.turboFrame === this.target) {\n if (DEBUG)\n console.debug(\n `kpop: redirecting ${this.target} to ${this.getAttribute(\"href\")}`\n );\n const a = document.createElement(\"A\");\n a.setAttribute(\"data-turbo-action\", \"replace\");\n this.targetElements[0].delegate.navigateFrame(a, this.getAttribute(\"href\"));\n } else {\n if (DEBUG)\n console.debug(`kpop: redirecting to ${this.getAttribute(\"href\")}`);\n Turbo.visit(this.getAttribute(\"href\"), {\n action: this.dataset.turboAction,\n });\n }\n};\n","import FrameController from \"../kpop/controllers/frame_controller\";\nimport ModalController from \"../kpop/controllers/modal_controller\";\nimport ScrimController from \"../kpop/controllers/scrim_controller\";\n\nimport \"./turbo_actions\";\n\nconst Definitions = [\n { identifier: \"kpop--frame\", controllerConstructor: FrameController },\n { identifier: \"kpop--modal\", controllerConstructor: ModalController },\n { identifier: \"scrim\", controllerConstructor: ScrimController },\n];\n\nexport { Definitions as default };\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport DEBUG from \"../debug\";\n\nexport default class Kpop__ModalController extends Controller {\n static values = {\n fallback_location: String,\n layout: String,\n };\n\n connect() {\n this.debug(\"connect\");\n\n if (this.layoutValue) {\n document.querySelector(\"#kpop\").classList.toggle(this.layoutValue, true);\n }\n }\n\n disconnect() {\n this.debug(\"disconnect\");\n\n if (this.layoutValue) {\n document.querySelector(\"#kpop\").classList.toggle(this.layoutValue, false);\n }\n }\n\n debug(event, ...args) {\n if (DEBUG) console.debug(`ModalController:${event}`, ...args);\n }\n}\n"],"names":["Modal","constructor","id","this","open","debug","dismiss","beforeVisit","frame","e","detail","url","popstate","state","pop","event","callback","promise","Promise","resolve","window","addEventListener","once","frameElement","document","getElementById","modalElement","querySelector","currentLocationValue","dataset","fallbackLocationValue","isCurrentLocation","history","turbo","Turbo","session","location","href","src","args","ContentModal","super","visitStarted","visit","scrimOutlet","hide","animate","URL","toString","baseURI","FrameModal","back","preventDefault","then","Kpop__FrameController","Controller","static","Boolean","connect","element","kpop","complete","pathname","disconnect","modal","scrimOutletConnected","scrim","scrimConnected","openValue","show","openValueChanged","parentElement","style","display","isOpen","opening","nextFrame","reason","dismissing","beforeFrameRender","newFrame","resume","beforeStreamRender","render","stream","frameLoad","isConnected","console","warn","requestAnimationFrame","ScrimController","captive","zIndex","Number","defaultZIndexValue","zIndexValue","defaultCaptiveValue","captiveValue","top","scrollY","dispatch","bubbles","showAnimating","hideAnimating","escape","key","defaultPrevented","previousPosition","body","position","previousTop","resetStyle","scrollTo","left","behavior","property","previousValue","setProperty","removeProperty","StreamModal","action","pushState","innerHTML","StreamRenderer","append","templateContent","targetElements","StreamActions","kpop_open","target","kpop_dismiss","kpop_redirect_to","turboFrame","a","createElement","setAttribute","delegate","navigateFrame","getAttribute","turboAction","Definitions","identifier","controllerConstructor","FrameController","fallback_location","String","layout","layoutValue","classList","toggle"],"mappings":"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"}
1
+ {"version":3,"file":"kpop.min.js","sources":["../../../javascript/kpop/modals/modal.js","../../../javascript/kpop/modals/content_modal.js","../../../javascript/kpop/modals/frame_modal.js","../../../javascript/kpop/controllers/frame_controller.js","../../../javascript/kpop/controllers/scrim_controller.js","../../../javascript/kpop/modals/stream_modal.js","../../../javascript/kpop/utils/stream_renderer.js","../../../javascript/kpop/turbo_actions.js","../../../javascript/kpop/application.js","../../../javascript/kpop/controllers/modal_controller.js"],"sourcesContent":["import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport DEBUG from \"../debug\";\n\nexport class Modal {\n constructor(id) {\n this.id = id;\n }\n\n async open() {\n this.debug(\"open\");\n }\n\n async dismiss() {\n this.debug(`dismiss`);\n }\n\n beforeVisit(frame, e) {\n this.debug(`before-visit`, e.detail.url);\n }\n\n popstate(frame, e) {\n this.debug(`popstate`, e.state);\n }\n\n async pop(event, callback) {\n this.debug(`pop`);\n\n const promise = new Promise((resolve) => {\n window.addEventListener(\n event,\n () => {\n resolve();\n },\n { once: true }\n );\n });\n\n callback();\n\n return promise;\n }\n\n get frameElement() {\n return document.getElementById(this.id);\n }\n\n get modalElement() {\n return this.frameElement?.querySelector(\"[data-controller*='kpop--modal']\");\n }\n\n get currentLocationValue() {\n return this.modalElement?.dataset[\"kpop-ModalCurrentLocationValue\"] || \"/\";\n }\n\n get fallbackLocationValue() {\n return this.modalElement?.dataset[\"kpop-ModalFallbackLocationValue\"] || \"/\";\n }\n\n get isCurrentLocation() {\n return (\n window.history.state?.turbo && Turbo.session.location.href === this.src\n );\n }\n\n debug(event, ...args) {\n if (DEBUG) console.debug(`${this.constructor.name}:${event}`, ...args);\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport { Modal } from \"./modal\";\n\nexport class ContentModal extends Modal {\n constructor(id, src = null) {\n super(id);\n\n if (src) this.src = src;\n }\n\n async dismiss() {\n await super.dismiss();\n\n if (this.visitStarted) {\n this.debug(\"skipping dismiss, visit started\");\n return;\n }\n if (!this.isCurrentLocation) {\n this.debug(\"skipping dismiss, not current location\");\n return;\n }\n\n return this.pop(\"turbo:load\", () => {\n this.debug(\"turbo-visit\", this.fallbackLocationValue);\n Turbo.visit(this.fallbackLocationValue);\n });\n\n // no specific close action required, this is turbo's responsibility\n }\n\n beforeVisit(frame, e) {\n super.beforeVisit(frame, e);\n\n this.visitStarted = true;\n\n frame.scrimOutlet.hide({ animate: false });\n }\n\n get src() {\n return new URL(\n this.currentLocationValue.toString(),\n document.baseURI\n ).toString();\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport { Modal } from \"./modal\";\n\nexport class FrameModal extends Modal {\n constructor(id, src) {\n super(id);\n this.src = src;\n }\n\n async dismiss() {\n await super.dismiss();\n\n if (!this.isCurrentLocation) {\n this.debug(\"skipping dismiss, not current location\");\n } else {\n await this.pop(\"turbo:load\", () => window.history.back());\n }\n\n // no specific close action required, this is turbo's responsibility\n }\n\n beforeVisit(frame, e) {\n super.beforeVisit(frame, e);\n\n e.preventDefault();\n\n frame.dismiss({ animate: false }).then(() => {\n Turbo.visit(e.detail.url);\n\n this.debug(\"before-visit-end\");\n });\n }\n\n popstate(frame, e) {\n super.popstate(frame, e);\n\n // Turbo will restore modal state, but we need to reset the scrim\n frame.scrimOutlet.hide({ animate: false });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport DEBUG from \"../debug\";\nimport { ContentModal } from \"../modals/content_modal\";\nimport { FrameModal } from \"../modals/frame_modal\";\n\nexport default class Kpop__FrameController extends Controller {\n static outlets = [\"scrim\"];\n static targets = [\"modal\"];\n static values = {\n open: Boolean,\n };\n\n connect() {\n this.debug(\"connect\", this.element.src);\n\n this.element.kpop = this;\n installNavigationInterception(this.element);\n\n // restoration visit\n if (this.element.src && this.element.complete) {\n this.debug(\"new frame modal\", this.element.src);\n this.open(new FrameModal(this.element.id, this.element.src), {\n animate: false,\n });\n } else {\n const element = this.element.querySelector(\n \"[data-controller*='kpop--modal']\"\n );\n if (element) {\n this.debug(\"new content modal\", window.location.pathname);\n this.open(new ContentModal(this.element.id), { animate: false });\n }\n }\n }\n\n disconnect() {\n this.debug(\"disconnect\");\n\n delete this.element.kpop;\n delete this.modal;\n }\n\n scrimOutletConnected(scrim) {\n this.debug(\"scrim-connected\");\n\n this.scrimConnected = true;\n\n if (this.openValue) {\n scrim.show({ animate: false });\n } else {\n scrim.hide({ animate: false });\n }\n }\n\n openValueChanged(open) {\n this.debug(\"open-changed\", open);\n\n this.element.parentElement.style.display = open ? \"flex\" : \"none\";\n }\n\n async open(modal, { animate = true } = {}) {\n if (this.isOpen) {\n this.debug(\"skip open as already open\");\n this.modal ||= modal;\n return false;\n }\n\n return (this.opening ||= this.#nextFrame(() =>\n this.#open(modal, { animate })\n ));\n }\n\n async dismiss({ animate = true, reason = \"\" } = {}) {\n if (!this.isOpen) {\n this.debug(\"skip dismiss as already closed\");\n return false;\n }\n\n return (this.dismissing ||= this.#nextFrame(() =>\n this.#dismiss({ animate, reason })\n ));\n }\n\n // EVENTS\n\n popstate(event) {\n this.modal?.popstate(this, event);\n }\n\n navigateFrame(element, location) {\n this.debug(\"navigate-frame\", this.element.src, location);\n\n // Ensure that turbo doesn't cache the frame in a loading state by cancelling\n // the current request (if any) by clearing the src.\n // Known issue: this won't work if the frame was previously rendering a useful src.\n if (this.element.hasAttribute(\"busy\")) {\n this.element.src = \"\";\n }\n\n // Delay turbo's navigateFrame until next tick to let the src change settle.\n return Promise.resolve();\n }\n\n beforeFrameRender(event) {\n this.debug(\"before-frame-render\", event.detail.newFrame.baseURI);\n\n event.preventDefault();\n\n this.dismiss({ animate: true, reason: \"before-frame-render\" }).then(() => {\n this.debug(\"resume-frame-render\", event.detail.newFrame.baseURI);\n event.detail.resume();\n });\n }\n\n beforeStreamRender(event) {\n this.debug(\"before-stream-render\", event.detail);\n\n const resume = event.detail.render;\n\n // Defer rendering until dismiss is complete.\n // Dismiss may change history so we need to wait for it to complete to avoid\n // losing DOM changes on restoration visits.\n event.detail.render = (stream) => {\n (this.dismissing || Promise.resolve()).then(() => {\n this.debug(\"stream-render\", stream);\n resume(stream);\n });\n };\n }\n\n beforeVisit(e) {\n this.debug(\"before-visit\", e.detail.url);\n\n // ignore visits to the current frame, these fire when the frame navigates\n if (e.detail.url === this.element.src) return;\n\n // ignore unless we're open\n if (!this.isOpen) return;\n\n this.modal.beforeVisit(this, e);\n }\n\n frameLoad(event) {\n this.debug(\"frame-load\");\n\n return this.open(new FrameModal(this.element.id, this.element.src), {\n animate: true,\n });\n }\n\n get isOpen() {\n return this.openValue && !this.dismissing;\n }\n\n async #open(modal, { animate = true } = {}) {\n this.debug(\"open-start\", { animate });\n\n const scrim = this.scrimConnected && this.scrimOutlet;\n\n this.modal = modal;\n this.openValue = true;\n\n await modal.open({ animate });\n await scrim?.show({ animate });\n\n delete this.opening;\n\n this.debug(\"open-end\");\n }\n\n async #dismiss({ animate = true, reason = \"\" } = {}) {\n this.debug(\"dismiss-start\", { animate, reason });\n\n // if this element is detached then we've experienced a turbo navigation\n if (!this.element.isConnected) {\n this.debug(\"skip dismiss, element detached\");\n return;\n }\n\n if (!this.modal) {\n console.warn(\"modal missing on dismiss\");\n if (DEBUG) debugger;\n }\n\n await this.scrimOutlet.hide({ animate });\n await this.modal?.dismiss();\n\n this.openValue = false;\n this.modal = null;\n delete this.dismissing;\n\n this.debug(\"dismiss-end\");\n }\n\n async #nextFrame(callback) {\n return new Promise(window.requestAnimationFrame).then(callback);\n }\n\n debug(event, ...args) {\n if (DEBUG) console.debug(`FrameController:${event}`, ...args);\n }\n}\n\n/**\n * Monkey patch for Turbo#FrameController.\n *\n * Intercept calls to navigateFrame(element, location) and ensures that src is\n * cleared if the frame is busy so that we don't restore an in-progress src on\n * restoration visits.\n *\n * See Turbo issue: https://github.com/hotwired/turbo/issues/1055\n *\n * @param frameElement turbo-frame element\n */\nfunction installNavigationInterception(frameElement) {\n if (frameElement.delegate._navigateFrame === undefined) {\n frameElement.delegate._navigateFrame = frameElement.delegate.navigateFrame;\n frameElement.delegate.navigateFrame = async (element, location) => {\n await frameElement.kpop?.navigateFrame(element, location);\n return frameElement.delegate._navigateFrame.call(\n frameElement.delegate,\n element,\n location\n );\n };\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport DEBUG from \"../debug\";\n\n/**\n * Scrim controller wraps an element that creates a whole page layer.\n * It is intended to be used behind a modal or nav drawer.\n *\n * If the Scrim element receives a click event, it automatically triggers \"scrim:hide\".\n *\n * You can show and hide the scrim programmatically by calling show/hide on the controller, e.g. using an outlet.\n *\n * If you need to respond to the scrim showing or hiding you should subscribe to \"scrim:show\" and \"scrim:hide\".\n */\nexport default class ScrimController extends Controller {\n static values = {\n open: Boolean,\n captive: Boolean,\n zIndex: Number,\n };\n\n connect() {\n if (DEBUG) console.debug(\"scrim:connect\");\n\n this.defaultZIndexValue = this.zIndexValue;\n this.defaultCaptiveValue = this.captiveValue;\n\n this.element.scrim = this;\n }\n\n disconnect() {\n if (DEBUG) console.debug(\"scrim:disconnect\");\n\n delete this.element.scrim;\n }\n\n async show({\n captive = this.defaultCaptiveValue,\n zIndex = this.defaultZIndexValue,\n top = window.scrollY,\n animate = true,\n } = {}) {\n if (DEBUG) console.debug(\"scrim:before-show\");\n\n // hide the scrim before opening the new one if it's already open\n if (this.openValue) {\n await this.hide({ animate });\n }\n\n // update internal state\n this.openValue = true;\n\n // notify listeners of pending request\n this.dispatch(\"show\", { bubbles: true });\n\n if (DEBUG) console.debug(\"scrim:show-start\");\n\n // update state, perform style updates\n this.#show(captive, zIndex, top);\n\n if (animate) {\n // animate opening\n // this will trigger an animationEnd event via CSS that completes the open\n this.element.dataset.showAnimating = \"\";\n\n await new Promise((resolve) => {\n this.element.addEventListener(\"animationend\", () => resolve(), {\n once: true,\n });\n });\n\n delete this.element.dataset.showAnimating;\n }\n\n if (DEBUG) console.debug(\"scrim:show-end\");\n }\n\n async hide({ animate = true } = {}) {\n if (!this.openValue || this.element.dataset.hideAnimating) return;\n\n if (DEBUG) console.debug(\"scrim:before-hide\");\n\n // notify listeners of pending request\n this.dispatch(\"hide\", { bubbles: true });\n\n if (DEBUG) console.debug(\"scrim:hide-start\");\n\n if (animate) {\n // set animation state\n // this will trigger an animationEnd event via CSS that completes the hide\n this.element.dataset.hideAnimating = \"\";\n\n await new Promise((resolve) => {\n this.element.addEventListener(\"animationend\", () => resolve(), {\n once: true,\n });\n });\n\n delete this.element.dataset.hideAnimating;\n }\n\n this.#hide();\n\n this.openValue = false;\n\n if (DEBUG) console.debug(\"scrim:hide-end\");\n }\n\n dismiss(event) {\n if (DEBUG) console.debug(\"scrim:dismiss\");\n\n if (!this.captiveValue) this.dispatch(\"dismiss\", { bubbles: true });\n }\n\n escape(event) {\n if (\n event.key === \"Escape\" &&\n !this.captiveValue &&\n !event.defaultPrevented\n ) {\n this.dispatch(\"dismiss\", { bubbles: true });\n }\n }\n\n /**\n * Clips body to viewport size and sets the z-index\n */\n #show(captive, zIndex, top) {\n this.captiveValue = captive;\n this.zIndexValue = zIndex;\n this.scrollY = top;\n\n this.previousPosition = document.body.style.position;\n this.previousTop = document.body.style.top;\n\n this.element.style.zIndex = this.zIndexValue;\n document.body.style.top = `-${top}px`;\n document.body.style.position = \"fixed\";\n }\n\n /**\n * Unclips body from viewport size and unsets the z-index\n */\n #hide() {\n this.captiveValue = this.defaultCaptiveValue;\n this.zIndexValue = this.defaultZIndexValue;\n\n resetStyle(this.element, \"z-index\", null);\n resetStyle(document.body, \"position\", null);\n resetStyle(document.body, \"top\", null);\n\n window.scrollTo({ left: 0, top: this.scrollY, behavior: \"instant\" });\n\n delete this.scrollY;\n delete this.previousPosition;\n delete this.previousTop;\n }\n}\n\nfunction resetStyle(element, property, previousValue) {\n if (previousValue) {\n element.style.setProperty(property, previousValue);\n } else {\n element.style.removeProperty(property);\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport { Modal } from \"./modal\";\n\nexport class StreamModal extends Modal {\n constructor(id, action) {\n super(id);\n\n this.action = action;\n }\n\n async open() {\n await super.open();\n\n window.history.pushState({ kpop: true, id: this.id }, \"\", window.location);\n }\n\n async dismiss() {\n await super.dismiss();\n\n if (this.isCurrentLocation) {\n await this.pop(\"popstate\", () => window.history.back());\n }\n\n this.frameElement.innerHTML = \"\";\n }\n\n beforeVisit(frame, e) {\n super.beforeVisit(frame, e);\n\n e.preventDefault();\n\n frame.dismiss({ animate: false }).then(() => {\n Turbo.visit(e.detail.url);\n\n this.debug(\"before-visit-end\");\n });\n }\n\n popstate(frame, e) {\n super.popstate(frame, e);\n\n frame.dismiss({ animate: true, reason: \"popstate\" });\n }\n\n get isCurrentLocation() {\n return window.history.state?.kpop && window.history.state?.id === this.id;\n }\n}\n","import DEBUG from \"../debug\";\n\nexport class StreamRenderer {\n constructor(frame, action) {\n this.frame = frame;\n this.action = action;\n }\n\n render() {\n if (DEBUG) console.debug(\"stream-renderer:render\");\n this.frame.src = \"\";\n this.frame.innerHTML = \"\";\n this.frame.append(this.action.templateContent);\n }\n}\n","import { Turbo } from \"@hotwired/turbo-rails\";\n\nimport DEBUG from \"./debug\";\n\nimport { StreamModal } from \"./modals/stream_modal\";\nimport { StreamRenderer } from \"./utils/stream_renderer\";\n\nfunction kpop(action) {\n return action.targetElements[0]?.kpop;\n}\n\nTurbo.StreamActions.kpop_open = function () {\n const animate = !kpop(this).openValue;\n\n kpop(this)\n ?.dismiss({ animate, reason: \"before-turbo-stream\" })\n .then(() => {\n new StreamRenderer(this.targetElements[0], this).render();\n kpop(this)?.open(new StreamModal(this.target, this), { animate });\n });\n};\n\nTurbo.StreamActions.kpop_dismiss = function () {\n kpop(this)?.dismiss({ reason: \"turbo_stream.kpop.dismiss\" });\n};\n\nTurbo.StreamActions.kpop_redirect_to = function () {\n if (this.dataset.turboFrame === this.target) {\n if (DEBUG)\n console.debug(\n `kpop: redirecting ${this.target} to ${this.getAttribute(\"href\")}`\n );\n const a = document.createElement(\"A\");\n a.setAttribute(\"data-turbo-action\", \"replace\");\n this.targetElements[0].delegate.navigateFrame(a, this.getAttribute(\"href\"));\n } else {\n if (DEBUG)\n console.debug(`kpop: redirecting to ${this.getAttribute(\"href\")}`);\n Turbo.visit(this.getAttribute(\"href\"), {\n action: this.dataset.turboAction,\n });\n }\n};\n","import FrameController from \"../kpop/controllers/frame_controller\";\nimport ModalController from \"../kpop/controllers/modal_controller\";\nimport ScrimController from \"../kpop/controllers/scrim_controller\";\n\nimport \"./turbo_actions\";\n\nconst Definitions = [\n { identifier: \"kpop--frame\", controllerConstructor: FrameController },\n { identifier: \"kpop--modal\", controllerConstructor: ModalController },\n { identifier: \"scrim\", controllerConstructor: ScrimController },\n];\n\nexport { Definitions as default };\n","import { Controller } from \"@hotwired/stimulus\";\n\nimport DEBUG from \"../debug\";\n\nexport default class Kpop__ModalController extends Controller {\n static values = {\n fallback_location: String,\n layout: String,\n };\n\n connect() {\n this.debug(\"connect\");\n\n if (this.layoutValue) {\n document.querySelector(\"#kpop\").classList.toggle(this.layoutValue, true);\n }\n }\n\n disconnect() {\n this.debug(\"disconnect\");\n\n if (this.layoutValue) {\n document.querySelector(\"#kpop\").classList.toggle(this.layoutValue, false);\n }\n }\n\n debug(event, ...args) {\n if (DEBUG) console.debug(`ModalController:${event}`, ...args);\n }\n}\n"],"names":["Modal","constructor","id","this","open","debug","dismiss","beforeVisit","frame","e","detail","url","popstate","state","pop","event","callback","promise","Promise","resolve","window","addEventListener","once","frameElement","document","getElementById","modalElement","querySelector","currentLocationValue","dataset","fallbackLocationValue","isCurrentLocation","history","turbo","Turbo","session","location","href","src","args","ContentModal","super","visitStarted","visit","scrimOutlet","hide","animate","URL","toString","baseURI","FrameModal","back","preventDefault","then","Kpop__FrameController","Controller","static","Boolean","connect","element","kpop","undefined","delegate","_navigateFrame","navigateFrame","async","call","complete","pathname","disconnect","modal","scrimOutletConnected","scrim","scrimConnected","openValue","show","openValueChanged","parentElement","style","display","isOpen","opening","nextFrame","reason","dismissing","hasAttribute","beforeFrameRender","newFrame","resume","beforeStreamRender","render","stream","frameLoad","isConnected","console","warn","requestAnimationFrame","ScrimController","captive","zIndex","Number","defaultZIndexValue","zIndexValue","defaultCaptiveValue","captiveValue","top","scrollY","dispatch","bubbles","showAnimating","hideAnimating","escape","key","defaultPrevented","previousPosition","body","position","previousTop","resetStyle","scrollTo","left","behavior","property","previousValue","setProperty","removeProperty","StreamModal","action","pushState","innerHTML","StreamRenderer","append","templateContent","targetElements","StreamActions","kpop_open","target","kpop_dismiss","kpop_redirect_to","turboFrame","a","createElement","setAttribute","getAttribute","turboAction","Definitions","identifier","controllerConstructor","FrameController","fallback_location","String","layout","layoutValue","classList","toggle"],"mappings":"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"}
@@ -15,6 +15,7 @@ export default class Kpop__FrameController extends Controller {
15
15
  this.debug("connect", this.element.src);
16
16
 
17
17
  this.element.kpop = this;
18
+ installNavigationInterception(this.element);
18
19
 
19
20
  // restoration visit
20
21
  if (this.element.src && this.element.complete) {
@@ -87,6 +88,20 @@ export default class Kpop__FrameController extends Controller {
87
88
  this.modal?.popstate(this, event);
88
89
  }
89
90
 
91
+ navigateFrame(element, location) {
92
+ this.debug("navigate-frame", this.element.src, location);
93
+
94
+ // Ensure that turbo doesn't cache the frame in a loading state by cancelling
95
+ // the current request (if any) by clearing the src.
96
+ // Known issue: this won't work if the frame was previously rendering a useful src.
97
+ if (this.element.hasAttribute("busy")) {
98
+ this.element.src = "";
99
+ }
100
+
101
+ // Delay turbo's navigateFrame until next tick to let the src change settle.
102
+ return Promise.resolve();
103
+ }
104
+
90
105
  beforeFrameRender(event) {
91
106
  this.debug("before-frame-render", event.detail.newFrame.baseURI);
92
107
 
@@ -186,3 +201,28 @@ export default class Kpop__FrameController extends Controller {
186
201
  if (DEBUG) console.debug(`FrameController:${event}`, ...args);
187
202
  }
188
203
  }
204
+
205
+ /**
206
+ * Monkey patch for Turbo#FrameController.
207
+ *
208
+ * Intercept calls to navigateFrame(element, location) and ensures that src is
209
+ * cleared if the frame is busy so that we don't restore an in-progress src on
210
+ * restoration visits.
211
+ *
212
+ * See Turbo issue: https://github.com/hotwired/turbo/issues/1055
213
+ *
214
+ * @param frameElement turbo-frame element
215
+ */
216
+ function installNavigationInterception(frameElement) {
217
+ if (frameElement.delegate._navigateFrame === undefined) {
218
+ frameElement.delegate._navigateFrame = frameElement.delegate.navigateFrame;
219
+ frameElement.delegate.navigateFrame = async (element, location) => {
220
+ await frameElement.kpop?.navigateFrame(element, location);
221
+ return frameElement.delegate._navigateFrame.call(
222
+ frameElement.delegate,
223
+ element,
224
+ location
225
+ );
226
+ };
227
+ }
228
+ }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Katalyst
4
4
  module Kpop
5
- VERSION = "3.0.0.beta.5"
5
+ VERSION = "3.0.0.beta.6"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katalyst-kpop
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.beta.5
4
+ version: 3.0.0.beta.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katalyst Interactive
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-30 00:00:00.000000000 Z
11
+ date: 2023-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: html-attributes-utils