turbo-rails 0.8.1 → 0.8.2

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: c262e76eb847e212773e7befcc963473e87b06f2bf01eefdff938cff52eb1779
4
- data.tar.gz: ced8870cfb3301bcd13b551f47bf327400780e9a72844547a482ff3207ca4481
3
+ metadata.gz: 44110a857a5e33eabc67331969cd39358dfc4a47ad0ffbce7e948ba2b29ea7ca
4
+ data.tar.gz: 3acfe3758be58ee628a3c74ceda13bb231bafed4d7692d42410566b148218a7a
5
5
  SHA512:
6
- metadata.gz: 29ef07542ceea019544fc6ecc3598452c21122d271c5805d211f2d932d449dc9288d09adaaf9ffcc910ddb1ab2feb53174a39adf8e80515efbe61eb2fde4833d
7
- data.tar.gz: 12685cf32b4aef76070124bb52705b508363f330d7e465e7466c3a727d07c8b0299c15f315297390b0561b6881d5310e4e60e656fe7fe1337f3cfa3fcd5f854c
6
+ metadata.gz: 8b2f35763464736733b817c718603e09bd2208cb5ec5523b7b42dac925617908d40bb574a0cfa855553eed835e897b0bb98650b70ade5dbbc5267618c6782d42
7
+ data.tar.gz: 5bd55a0bac8945cb99e406ef8b862af692109786e3b7afe6b8af1f7a7ce24c0f5b8efce27f75c9ddf1def964724969fbd241ab0a934ca26d336c4df857bb8e8f
data/README.md CHANGED
@@ -61,7 +61,7 @@ import "@hotwired/turbo-rails"
61
61
 
62
62
  ## Usage
63
63
 
64
- You can watch [the video introduction to Hotwire](https://hotwired.dev/#screencast), which focuses extensively on demonstration Turbo in a Rails demo. Then you should familiarize yourself with [Turbo handbook](https://turbo.hotwired.dev/handbook/introduction) to understand Drive, Frames, and Streams in-depth. Finally, dive into the code documentation by starting with [`Turbo::FramesHelper`](https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/frames_helper.rb), [`Turbo::StreamsHelper`](https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/streams_helper.rb), [`Turbo::Streams::TagBuilder`](https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb), and [`Turbo::Broadcastable`](https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb).
64
+ You can watch [the video introduction to Hotwire](https://hotwired.dev/#screencast), which focuses extensively on demonstrating Turbo in a Rails demo. Then you should familiarize yourself with [Turbo handbook](https://turbo.hotwired.dev/handbook/introduction) to understand Drive, Frames, and Streams in-depth. Finally, dive into the code documentation by starting with [`Turbo::FramesHelper`](https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/frames_helper.rb), [`Turbo::StreamsHelper`](https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/streams_helper.rb), [`Turbo::Streams::TagBuilder`](https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb), and [`Turbo::Broadcastable`](https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb).
65
65
 
66
66
 
67
67
  ## Compatibility with Rails UJS
@@ -0,0 +1,24 @@
1
+ !function(){if(void 0===window.Reflect||void 0===window.customElements||window.customElements.polyfillWrapFlushCallback)return;const e=HTMLElement,t=function(){return Reflect.construct(e,[],this.constructor)};window.HTMLElement=t,HTMLElement.prototype=e.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,e)}();const e=new WeakMap;function t(t){const s=function(e){const t=e instanceof Element?e:e instanceof Node?e.parentElement:null,s=t?t.closest("input, button"):null;return"submit"==(null==s?void 0:s.type)?s:null}(t.target);s&&s.form&&e.set(s.form,s)}var s,i,r,n,o,a;!function(){if("submitter"in Event.prototype)return;let s;if("SubmitEvent"in window&&/Apple Computer/.test(navigator.vendor))s=window.SubmitEvent.prototype;else{if("SubmitEvent"in window)return;s=window.Event.prototype}addEventListener("click",t,!0),Object.defineProperty(s,"submitter",{get(){if("submit"==this.type&&this.target instanceof HTMLFormElement)return e.get(this.target)}})}(),function(e){e.eager="eager",e.lazy="lazy"}(s||(s={}));class c extends HTMLElement{constructor(){super(),this.loaded=Promise.resolve(),this.delegate=new c.delegateConstructor(this)}static get observedAttributes(){return["disabled","loading","src"]}connectedCallback(){this.delegate.connect()}disconnectedCallback(){this.delegate.disconnect()}reload(){const{src:e}=this;this.src=null,this.src=e}attributeChangedCallback(e){"loading"==e?this.delegate.loadingStyleChanged():"src"==e?this.delegate.sourceURLChanged():this.delegate.disabledChanged()}get src(){return this.getAttribute("src")}set src(e){e?this.setAttribute("src",e):this.removeAttribute("src")}get loading(){return function(e){switch(e.toLowerCase()){case"lazy":return s.lazy;default:return s.eager}}(this.getAttribute("loading")||"")}set loading(e){e?this.setAttribute("loading",e):this.removeAttribute("loading")}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get autoscroll(){return this.hasAttribute("autoscroll")}set autoscroll(e){e?this.setAttribute("autoscroll",""):this.removeAttribute("autoscroll")}get complete(){return!this.delegate.isLoading}get isActive(){return this.ownerDocument===document&&!this.isPreview}get isPreview(){var e,t;return null===(t=null===(e=this.ownerDocument)||void 0===e?void 0:e.documentElement)||void 0===t?void 0:t.hasAttribute("data-turbo-preview")}}function l(e){return new URL(e.toString(),document.baseURI)}function h(e){let t;return e.hash?e.hash.slice(1):(t=e.href.match(/#(.*)$/))?t[1]:void 0}function d(e){return(function(e){return function(e){return e.pathname.split("/").slice(1)}(e).slice(-1)[0]}(e).match(/\.[^.]*$/)||[])[0]||""}function u(e,t){const s=function(e){return t=e.origin+e.pathname,t.endsWith("/")?t:t+"/";var t}(t);return e.href===l(s).href||e.href.startsWith(s)}function m(e){const t=h(e);return null!=t?e.href.slice(0,-(t.length+1)):e.href}function p(e){return m(e)}class g{constructor(e){this.response=e}get succeeded(){return this.response.ok}get failed(){return!this.succeeded}get clientError(){return this.statusCode>=400&&this.statusCode<=499}get serverError(){return this.statusCode>=500&&this.statusCode<=599}get redirected(){return this.response.redirected}get location(){return l(this.response.url)}get isHTML(){return this.contentType&&this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/)}get statusCode(){return this.response.status}get contentType(){return this.header("Content-Type")}get responseText(){return this.response.clone().text()}get responseHTML(){return this.isHTML?this.response.clone().text():Promise.resolve(void 0)}header(e){return this.response.headers.get(e)}}function f(e,{target:t,cancelable:s,detail:i}={}){const r=new CustomEvent(e,{cancelable:s,bubbles:!0,detail:i});return t&&t.isConnected?t.dispatchEvent(r):document.documentElement.dispatchEvent(r),r}function v(){return new Promise((e=>requestAnimationFrame((()=>e()))))}function b(e=""){return(new DOMParser).parseFromString(e,"text/html")}function S(e,...t){const s=function(e,t){return e.reduce(((e,s,i)=>e+s+(null==t[i]?"":t[i])),"")}(e,t).replace(/^\n/,"").split("\n"),i=s[0].match(/^\s+/),r=i?i[0].length:0;return s.map((e=>e.slice(r))).join("\n")}function w(){return Array.apply(null,{length:36}).map(((e,t)=>8==t||13==t||18==t||23==t?"-":14==t?"4":19==t?(Math.floor(4*Math.random())+8).toString(16):Math.floor(15*Math.random()).toString(16))).join("")}!function(e){e[e.get=0]="get",e[e.post=1]="post",e[e.put=2]="put",e[e.patch=3]="patch",e[e.delete=4]="delete"}(i||(i={}));class y{constructor(e,t,s,i=new URLSearchParams,r=null){this.abortController=new AbortController,this.resolveRequestPromise=e=>{},this.delegate=e,this.method=t,this.headers=this.defaultHeaders,this.isIdempotent?this.url=function(e,t){const s=new URLSearchParams(e.search);for(const[i,r]of t)r instanceof File||(s.has(i)?(s.delete(i),e.searchParams.set(i,r)):e.searchParams.append(i,r));return e}(s,[...i.entries()]):(this.body=i,this.url=s),this.target=r}get location(){return this.url}get params(){return this.url.searchParams}get entries(){return this.body?Array.from(this.body.entries()):[]}cancel(){this.abortController.abort()}async perform(){var e,t;const{fetchOptions:s}=this;null===(t=(e=this.delegate).prepareHeadersForRequest)||void 0===t||t.call(e,this.headers,this),await this.allowRequestToBeIntercepted(s);try{this.delegate.requestStarted(this);const e=await fetch(this.url.href,s);return await this.receive(e)}catch(e){if("AbortError"!==e.name)throw this.delegate.requestErrored(this,e),e}finally{this.delegate.requestFinished(this)}}async receive(e){const t=new g(e);return f("turbo:before-fetch-response",{cancelable:!0,detail:{fetchResponse:t},target:this.target}).defaultPrevented?this.delegate.requestPreventedHandlingResponse(this,t):t.succeeded?this.delegate.requestSucceededWithResponse(this,t):this.delegate.requestFailedWithResponse(this,t),t}get fetchOptions(){var e;return{method:i[this.method].toUpperCase(),credentials:"same-origin",headers:this.headers,redirect:"follow",body:this.body,signal:this.abortSignal,referrer:null===(e=this.delegate.referrer)||void 0===e?void 0:e.href}}get defaultHeaders(){return{Accept:"text/html, application/xhtml+xml"}}get isIdempotent(){return this.method==i.get}get abortSignal(){return this.abortController.signal}async allowRequestToBeIntercepted(e){const t=new Promise((e=>this.resolveRequestPromise=e));f("turbo:before-fetch-request",{cancelable:!0,detail:{fetchOptions:e,url:this.url.href,resume:this.resolveRequestPromise},target:this.target}).defaultPrevented&&await t}}class E{constructor(e,t){this.started=!1,this.intersect=e=>{const t=e.slice(-1)[0];(null==t?void 0:t.isIntersecting)&&this.delegate.elementAppearedInViewport(this.element)},this.delegate=e,this.element=t,this.intersectionObserver=new IntersectionObserver(this.intersect)}start(){this.started||(this.started=!0,this.intersectionObserver.observe(this.element))}stop(){this.started&&(this.started=!1,this.intersectionObserver.unobserve(this.element))}}class R{constructor(e){this.templateElement=document.createElement("template"),this.templateElement.innerHTML=e}static wrap(e){return"string"==typeof e?new this(e):e}get fragment(){const e=document.createDocumentFragment();for(const t of this.foreignElements)e.appendChild(document.importNode(t,!0));return e}get foreignElements(){return this.templateChildren.reduce(((e,t)=>"turbo-stream"==t.tagName.toLowerCase()?[...e,t]:e),[])}get templateChildren(){return Array.from(this.templateElement.content.children)}}R.contentType="text/vnd.turbo-stream.html",function(e){e[e.initialized=0]="initialized",e[e.requesting=1]="requesting",e[e.waiting=2]="waiting",e[e.receiving=3]="receiving",e[e.stopping=4]="stopping",e[e.stopped=5]="stopped"}(r||(r={})),function(e){e.urlEncoded="application/x-www-form-urlencoded",e.multipart="multipart/form-data",e.plain="text/plain"}(n||(n={}));class C{constructor(e,t,s,i=!1){this.state=r.initialized,this.delegate=e,this.formElement=t,this.submitter=s,this.formData=function(e,t){const s=new FormData(e),i=null==t?void 0:t.getAttribute("name"),r=null==t?void 0:t.getAttribute("value");i&&null!=r&&s.get(i)!=r&&s.append(i,r);return s}(t,s),this.fetchRequest=new y(this,this.method,this.location,this.body,this.formElement),this.mustRedirect=i}get method(){var e;return function(e){switch(e.toLowerCase()){case"get":return i.get;case"post":return i.post;case"put":return i.put;case"patch":return i.patch;case"delete":return i.delete}}(((null===(e=this.submitter)||void 0===e?void 0:e.getAttribute("formmethod"))||this.formElement.getAttribute("method")||"").toLowerCase())||i.get}get action(){var e;const t="string"==typeof this.formElement.action?this.formElement.action:null;return(null===(e=this.submitter)||void 0===e?void 0:e.getAttribute("formaction"))||this.formElement.getAttribute("action")||t||""}get location(){return l(this.action)}get body(){return this.enctype==n.urlEncoded||this.method==i.get?new URLSearchParams(this.stringFormData):this.formData}get enctype(){var e;return function(e){switch(e.toLowerCase()){case n.multipart:return n.multipart;case n.plain:return n.plain;default:return n.urlEncoded}}((null===(e=this.submitter)||void 0===e?void 0:e.getAttribute("formenctype"))||this.formElement.enctype)}get isIdempotent(){return this.fetchRequest.isIdempotent}get stringFormData(){return[...this.formData].reduce(((e,[t,s])=>e.concat("string"==typeof s?[[t,s]]:[])),[])}async start(){const{initialized:e,requesting:t}=r;if(this.state==e)return this.state=t,this.fetchRequest.perform()}stop(){const{stopping:e,stopped:t}=r;if(this.state!=e&&this.state!=t)return this.state=e,this.fetchRequest.cancel(),!0}prepareHeadersForRequest(e,t){if(!t.isIdempotent){const t=function(e){if(null!=e){const t=(document.cookie?document.cookie.split("; "):[]).find((t=>t.startsWith(e)));if(t){const e=t.split("=").slice(1).join("=");return e?decodeURIComponent(e):void 0}}}(L("csrf-param"))||L("csrf-token");t&&(e["X-CSRF-Token"]=t),e.Accept=[R.contentType,e.Accept].join(", ")}}requestStarted(e){this.state=r.waiting,f("turbo:submit-start",{target:this.formElement,detail:{formSubmission:this}}),this.delegate.formSubmissionStarted(this)}requestPreventedHandlingResponse(e,t){this.result={success:t.succeeded,fetchResponse:t}}requestSucceededWithResponse(e,t){if(t.clientError||t.serverError)this.delegate.formSubmissionFailedWithResponse(this,t);else if(this.requestMustRedirect(e)&&function(e){return 200==e.statusCode&&!e.redirected}(t)){const e=new Error("Form responses must redirect to another location");this.delegate.formSubmissionErrored(this,e)}else this.state=r.receiving,this.result={success:!0,fetchResponse:t},this.delegate.formSubmissionSucceededWithResponse(this,t)}requestFailedWithResponse(e,t){this.result={success:!1,fetchResponse:t},this.delegate.formSubmissionFailedWithResponse(this,t)}requestErrored(e,t){this.result={success:!1,error:t},this.delegate.formSubmissionErrored(this,t)}requestFinished(e){this.state=r.stopped,f("turbo:submit-end",{target:this.formElement,detail:Object.assign({formSubmission:this},this.result)}),this.delegate.formSubmissionFinished(this)}requestMustRedirect(e){return!e.isIdempotent&&this.mustRedirect}}function L(e){const t=document.querySelector(`meta[name="${e}"]`);return t&&t.content}class A{constructor(e){this.element=e}get children(){return[...this.element.children]}hasAnchor(e){return null!=this.getElementForAnchor(e)}getElementForAnchor(e){return e?this.element.querySelector(`[id='${e}'], a[name='${e}']`):null}get isConnected(){return this.element.isConnected}get firstAutofocusableElement(){return this.element.querySelector("[autofocus]")}get permanentElements(){return[...this.element.querySelectorAll("[id][data-turbo-permanent]")]}getPermanentElementById(e){return this.element.querySelector(`#${e}[data-turbo-permanent]`)}getPermanentElementMapForSnapshot(e){const t={};for(const s of this.permanentElements){const{id:i}=s,r=e.getPermanentElementById(i);r&&(t[i]=[s,r])}return t}}class P{constructor(e,t){this.submitBubbled=e=>{const t=e.target;if(t instanceof HTMLFormElement&&t.closest("turbo-frame, html")==this.element){const s=e.submitter||void 0;this.delegate.shouldInterceptFormSubmission(t,s)&&(e.preventDefault(),e.stopImmediatePropagation(),this.delegate.formSubmissionIntercepted(t,s))}},this.delegate=e,this.element=t}start(){this.element.addEventListener("submit",this.submitBubbled)}stop(){this.element.removeEventListener("submit",this.submitBubbled)}}class T{constructor(e,t){this.resolveRenderPromise=e=>{},this.resolveInterceptionPromise=e=>{},this.delegate=e,this.element=t}scrollToAnchor(e){const t=this.snapshot.getElementForAnchor(e);t?(this.scrollToElement(t),this.focusElement(t)):this.scrollToPosition({x:0,y:0})}scrollToAnchorFromLocation(e){this.scrollToAnchor(h(e))}scrollToElement(e){e.scrollIntoView()}focusElement(e){e instanceof HTMLElement&&(e.hasAttribute("tabindex")?e.focus():(e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")))}scrollToPosition({x:e,y:t}){this.scrollRoot.scrollTo(e,t)}scrollToTop(){this.scrollToPosition({x:0,y:0})}get scrollRoot(){return window}async render(e){const{isPreview:t,shouldRender:s,newSnapshot:i}=e;if(s)try{this.renderPromise=new Promise((e=>this.resolveRenderPromise=e)),this.renderer=e,this.prepareToRenderSnapshot(e);const s=new Promise((e=>this.resolveInterceptionPromise=e));this.delegate.allowsImmediateRender(i,this.resolveInterceptionPromise)||await s,await this.renderSnapshot(e),this.delegate.viewRenderedSnapshot(i,t),this.finishRenderingSnapshot(e)}finally{delete this.renderer,this.resolveRenderPromise(void 0),delete this.renderPromise}else this.invalidate()}invalidate(){this.delegate.viewInvalidated()}prepareToRenderSnapshot(e){this.markAsPreview(e.isPreview),e.prepareToRender()}markAsPreview(e){e?this.element.setAttribute("data-turbo-preview",""):this.element.removeAttribute("data-turbo-preview")}async renderSnapshot(e){await e.render()}finishRenderingSnapshot(e){e.finishRendering()}}class k extends T{invalidate(){this.element.innerHTML=""}get snapshot(){return new A(this.element)}}class I{constructor(e,t){this.clickBubbled=e=>{this.respondsToEventTarget(e.target)?this.clickEvent=e:delete this.clickEvent},this.linkClicked=e=>{this.clickEvent&&this.respondsToEventTarget(e.target)&&e.target instanceof Element&&this.delegate.shouldInterceptLinkClick(e.target,e.detail.url)&&(this.clickEvent.preventDefault(),e.preventDefault(),this.delegate.linkClickIntercepted(e.target,e.detail.url)),delete this.clickEvent},this.willVisit=()=>{delete this.clickEvent},this.delegate=e,this.element=t}start(){this.element.addEventListener("click",this.clickBubbled),document.addEventListener("turbo:click",this.linkClicked),document.addEventListener("turbo:before-visit",this.willVisit)}stop(){this.element.removeEventListener("click",this.clickBubbled),document.removeEventListener("turbo:click",this.linkClicked),document.removeEventListener("turbo:before-visit",this.willVisit)}respondsToEventTarget(e){const t=e instanceof Element?e:e instanceof Node?e.parentElement:null;return t&&t.closest("turbo-frame, html")==this.element}}class F{constructor(e,t,s){this.currentSnapshot=e,this.newSnapshot=t,this.isPreview=s,this.promise=new Promise(((e,t)=>this.resolvingFunctions={resolve:e,reject:t}))}get shouldRender(){return!0}prepareToRender(){}finishRendering(){this.resolvingFunctions&&(this.resolvingFunctions.resolve(),delete this.resolvingFunctions)}createScriptElement(e){if("false"==e.getAttribute("data-turbo-eval"))return e;{const t=document.createElement("script");return this.cspNonce&&(t.nonce=this.cspNonce),t.textContent=e.textContent,t.async=!1,function(e,t){for(const{name:s,value:i}of[...t.attributes])e.setAttribute(s,i)}(t,e),t}}preservingPermanentElements(e){(class{constructor(e){this.permanentElementMap=e}static preservingPermanentElements(e,t){const s=new this(e);s.enter(),t(),s.leave()}enter(){for(const e in this.permanentElementMap){const[,t]=this.permanentElementMap[e];this.replaceNewPermanentElementWithPlaceholder(t)}}leave(){for(const e in this.permanentElementMap){const[t]=this.permanentElementMap[e];this.replaceCurrentPermanentElementWithClone(t),this.replacePlaceholderWithPermanentElement(t)}}replaceNewPermanentElementWithPlaceholder(e){const t=function(e){const t=document.createElement("meta");return t.setAttribute("name","turbo-permanent-placeholder"),t.setAttribute("content",e.id),t}(e);e.replaceWith(t)}replaceCurrentPermanentElementWithClone(e){const t=e.cloneNode(!0);e.replaceWith(t)}replacePlaceholderWithPermanentElement(e){const t=this.getPlaceholderById(e.id);null==t||t.replaceWith(e)}getPlaceholderById(e){return this.placeholders.find((t=>t.content==e))}get placeholders(){return[...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")]}}).preservingPermanentElements(this.permanentElementMap,e)}focusFirstAutofocusableElement(){const e=this.connectedSnapshot.firstAutofocusableElement;(function(e){return e&&"function"==typeof e.focus})(e)&&e.focus()}get connectedSnapshot(){return this.newSnapshot.isConnected?this.newSnapshot:this.currentSnapshot}get currentElement(){return this.currentSnapshot.element}get newElement(){return this.newSnapshot.element}get permanentElementMap(){return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot)}get cspNonce(){var e;return null===(e=document.head.querySelector('meta[name="csp-nonce"]'))||void 0===e?void 0:e.getAttribute("content")}}class M extends F{get shouldRender(){return!0}async render(){await v(),this.preservingPermanentElements((()=>{this.loadFrameElement()})),this.scrollFrameIntoView(),await v(),this.focusFirstAutofocusableElement(),await v(),this.activateScriptElements()}loadFrameElement(){var e;const t=document.createRange();t.selectNodeContents(this.currentElement),t.deleteContents();const s=this.newElement,i=null===(e=s.ownerDocument)||void 0===e?void 0:e.createRange();i&&(i.selectNodeContents(s),this.currentElement.appendChild(i.extractContents()))}scrollFrameIntoView(){if(this.currentElement.autoscroll||this.newElement.autoscroll){const s=this.currentElement.firstElementChild,i=(e=this.currentElement.getAttribute("data-autoscroll-block"),t="end","end"==e||"start"==e||"center"==e||"nearest"==e?e:t);if(s)return s.scrollIntoView({block:i}),!0}var e,t;return!1}activateScriptElements(){for(const e of this.newScriptElements){const t=this.createScriptElement(e);e.replaceWith(t)}}get newScriptElements(){return this.currentElement.querySelectorAll("script")}}class H{constructor(){this.hiding=!1,this.value=0,this.visible=!1,this.trickle=()=>{this.setValue(this.value+Math.random()/100)},this.stylesheetElement=this.createStylesheetElement(),this.progressElement=this.createProgressElement(),this.installStylesheetElement(),this.setValue(0)}static get defaultCSS(){return S`
2
+ .turbo-progress-bar {
3
+ position: fixed;
4
+ display: block;
5
+ top: 0;
6
+ left: 0;
7
+ height: 3px;
8
+ background: #0076ff;
9
+ z-index: 9999;
10
+ transition:
11
+ width ${H.animationDuration}ms ease-out,
12
+ opacity ${H.animationDuration/2}ms ${H.animationDuration/2}ms ease-in;
13
+ transform: translate3d(0, 0, 0);
14
+ }
15
+ `}show(){this.visible||(this.visible=!0,this.installProgressElement(),this.startTrickling())}hide(){this.visible&&!this.hiding&&(this.hiding=!0,this.fadeProgressElement((()=>{this.uninstallProgressElement(),this.stopTrickling(),this.visible=!1,this.hiding=!1})))}setValue(e){this.value=e,this.refresh()}installStylesheetElement(){document.head.insertBefore(this.stylesheetElement,document.head.firstChild)}installProgressElement(){this.progressElement.style.width="0",this.progressElement.style.opacity="1",document.documentElement.insertBefore(this.progressElement,document.body),this.refresh()}fadeProgressElement(e){this.progressElement.style.opacity="0",setTimeout(e,1.5*H.animationDuration)}uninstallProgressElement(){this.progressElement.parentNode&&document.documentElement.removeChild(this.progressElement)}startTrickling(){this.trickleInterval||(this.trickleInterval=window.setInterval(this.trickle,H.animationDuration))}stopTrickling(){window.clearInterval(this.trickleInterval),delete this.trickleInterval}refresh(){requestAnimationFrame((()=>{this.progressElement.style.width=10+90*this.value+"%"}))}createStylesheetElement(){const e=document.createElement("style");return e.type="text/css",e.textContent=H.defaultCSS,e}createProgressElement(){const e=document.createElement("div");return e.className="turbo-progress-bar",e}}H.animationDuration=300;class B extends A{constructor(){super(...arguments),this.detailsByOuterHTML=this.children.filter((e=>!function(e){return"noscript"==e.tagName.toLowerCase()}(e))).map((e=>function(e){e.hasAttribute("nonce")&&e.setAttribute("nonce","");return e}(e))).reduce(((e,t)=>{const{outerHTML:s}=t,i=s in e?e[s]:{type:q(t),tracked:O(t),elements:[]};return Object.assign(Object.assign({},e),{[s]:Object.assign(Object.assign({},i),{elements:[...i.elements,t]})})}),{})}get trackedElementSignature(){return Object.keys(this.detailsByOuterHTML).filter((e=>this.detailsByOuterHTML[e].tracked)).join("")}getScriptElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("script",e)}getStylesheetElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("stylesheet",e)}getElementsMatchingTypeNotInSnapshot(e,t){return Object.keys(this.detailsByOuterHTML).filter((e=>!(e in t.detailsByOuterHTML))).map((e=>this.detailsByOuterHTML[e])).filter((({type:t})=>t==e)).map((({elements:[e]})=>e))}get provisionalElements(){return Object.keys(this.detailsByOuterHTML).reduce(((e,t)=>{const{type:s,tracked:i,elements:r}=this.detailsByOuterHTML[t];return null!=s||i?r.length>1?[...e,...r.slice(1)]:e:[...e,...r]}),[])}getMetaValue(e){const t=this.findMetaElementByName(e);return t?t.getAttribute("content"):null}findMetaElementByName(e){return Object.keys(this.detailsByOuterHTML).reduce(((t,s)=>{const{elements:[i]}=this.detailsByOuterHTML[s];return function(e,t){return"meta"==e.tagName.toLowerCase()&&e.getAttribute("name")==t}(i,e)?i:t}),void 0)}}function q(e){return function(e){return"script"==e.tagName.toLowerCase()}(e)?"script":function(e){const t=e.tagName.toLowerCase();return"style"==t||"link"==t&&"stylesheet"==e.getAttribute("rel")}(e)?"stylesheet":void 0}function O(e){return"reload"==e.getAttribute("data-turbo-track")}class D extends A{constructor(e,t){super(e),this.headSnapshot=t}static fromHTMLString(e=""){return this.fromDocument(b(e))}static fromElement(e){return this.fromDocument(e.ownerDocument)}static fromDocument({head:e,body:t}){return new this(t,new B(e))}clone(){return new D(this.element.cloneNode(!0),this.headSnapshot)}get headElement(){return this.headSnapshot.element}get rootLocation(){var e;return l(null!==(e=this.getSetting("root"))&&void 0!==e?e:"/")}get cacheControlValue(){return this.getSetting("cache-control")}get isPreviewable(){return"no-preview"!=this.cacheControlValue}get isCacheable(){return"no-cache"!=this.cacheControlValue}get isVisitable(){return"reload"!=this.getSetting("visit-control")}getSetting(e){return this.headSnapshot.getMetaValue(`turbo-${e}`)}}!function(e){e.visitStart="visitStart",e.requestStart="requestStart",e.requestEnd="requestEnd",e.visitEnd="visitEnd"}(o||(o={})),function(e){e.initialized="initialized",e.started="started",e.canceled="canceled",e.failed="failed",e.completed="completed"}(a||(a={}));const W={action:"advance",historyChanged:!1};var V,N;!function(e){e[e.networkFailure=0]="networkFailure",e[e.timeoutFailure=-1]="timeoutFailure",e[e.contentTypeMismatch=-2]="contentTypeMismatch"}(V||(V={}));class x{constructor(e,t,s,i={}){this.identifier=w(),this.timingMetrics={},this.followedRedirect=!1,this.historyChanged=!1,this.scrolled=!1,this.snapshotCached=!1,this.state=a.initialized,this.delegate=e,this.location=t,this.restorationIdentifier=s||w();const{action:r,historyChanged:n,referrer:o,snapshotHTML:c,response:l}=Object.assign(Object.assign({},W),i);this.action=r,this.historyChanged=n,this.referrer=o,this.snapshotHTML=c,this.response=l,this.isSamePage=this.delegate.locationWithActionIsSamePage(this.location,this.action)}get adapter(){return this.delegate.adapter}get view(){return this.delegate.view}get history(){return this.delegate.history}get restorationData(){return this.history.getRestorationDataForIdentifier(this.restorationIdentifier)}get silent(){return this.isSamePage}start(){this.state==a.initialized&&(this.recordTimingMetric(o.visitStart),this.state=a.started,this.adapter.visitStarted(this),this.delegate.visitStarted(this))}cancel(){this.state==a.started&&(this.request&&this.request.cancel(),this.cancelRender(),this.state=a.canceled)}complete(){this.state==a.started&&(this.recordTimingMetric(o.visitEnd),this.state=a.completed,this.adapter.visitCompleted(this),this.delegate.visitCompleted(this),this.followRedirect())}fail(){this.state==a.started&&(this.state=a.failed,this.adapter.visitFailed(this))}changeHistory(){var e;if(!this.historyChanged){const t=this.location.href===(null===(e=this.referrer)||void 0===e?void 0:e.href)?"replace":this.action,s=this.getHistoryMethodForAction(t);this.history.update(s,this.location,this.restorationIdentifier),this.historyChanged=!0}}issueRequest(){this.hasPreloadedResponse()?this.simulateRequest():this.shouldIssueRequest()&&!this.request&&(this.request=new y(this,i.get,this.location),this.request.perform())}simulateRequest(){this.response&&(this.startRequest(),this.recordResponse(),this.finishRequest())}startRequest(){this.recordTimingMetric(o.requestStart),this.adapter.visitRequestStarted(this)}recordResponse(e=this.response){if(this.response=e,e){const{statusCode:t}=e;U(t)?this.adapter.visitRequestCompleted(this):this.adapter.visitRequestFailedWithStatusCode(this,t)}}finishRequest(){this.recordTimingMetric(o.requestEnd),this.adapter.visitRequestFinished(this)}loadResponse(){if(this.response){const{statusCode:e,responseHTML:t}=this.response;this.render((async()=>{this.cacheSnapshot(),this.view.renderPromise&&await this.view.renderPromise,U(e)&&null!=t?(await this.view.renderPage(D.fromHTMLString(t)),this.adapter.visitRendered(this),this.complete()):(await this.view.renderError(D.fromHTMLString(t)),this.adapter.visitRendered(this),this.fail())}))}}getCachedSnapshot(){const e=this.view.getCachedSnapshotForLocation(this.location)||this.getPreloadedSnapshot();if(e&&(!h(this.location)||e.hasAnchor(h(this.location)))&&("restore"==this.action||e.isPreviewable))return e}getPreloadedSnapshot(){if(this.snapshotHTML)return D.fromHTMLString(this.snapshotHTML)}hasCachedSnapshot(){return null!=this.getCachedSnapshot()}loadCachedSnapshot(){const e=this.getCachedSnapshot();if(e){const t=this.shouldIssueRequest();this.render((async()=>{this.cacheSnapshot(),this.isSamePage?this.adapter.visitRendered(this):(this.view.renderPromise&&await this.view.renderPromise,await this.view.renderPage(e,t),this.adapter.visitRendered(this),t||this.complete())}))}}followRedirect(){this.redirectedToLocation&&!this.followedRedirect&&(this.adapter.visitProposedToLocation(this.redirectedToLocation,{action:"replace",response:this.response}),this.followedRedirect=!0)}goToSamePageAnchor(){this.isSamePage&&this.render((async()=>{this.cacheSnapshot(),this.adapter.visitRendered(this)}))}requestStarted(){this.startRequest()}requestPreventedHandlingResponse(e,t){}async requestSucceededWithResponse(e,t){const s=await t.responseHTML;null==s?this.recordResponse({statusCode:V.contentTypeMismatch}):(this.redirectedToLocation=t.redirected?t.location:void 0,this.recordResponse({statusCode:t.statusCode,responseHTML:s}))}async requestFailedWithResponse(e,t){const s=await t.responseHTML;null==s?this.recordResponse({statusCode:V.contentTypeMismatch}):this.recordResponse({statusCode:t.statusCode,responseHTML:s})}requestErrored(e,t){this.recordResponse({statusCode:V.networkFailure})}requestFinished(){this.finishRequest()}performScroll(){this.scrolled||("restore"==this.action?this.scrollToRestoredPosition()||this.scrollToAnchor()||this.view.scrollToTop():this.scrollToAnchor()||this.view.scrollToTop(),this.isSamePage&&this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation,this.location),this.scrolled=!0)}scrollToRestoredPosition(){const{scrollPosition:e}=this.restorationData;if(e)return this.view.scrollToPosition(e),!0}scrollToAnchor(){const e=h(this.location);if(null!=e)return this.view.scrollToAnchor(e),!0}recordTimingMetric(e){this.timingMetrics[e]=(new Date).getTime()}getTimingMetrics(){return Object.assign({},this.timingMetrics)}getHistoryMethodForAction(e){switch(e){case"replace":return history.replaceState;case"advance":case"restore":return history.pushState}}hasPreloadedResponse(){return"object"==typeof this.response}shouldIssueRequest(){return!this.isSamePage&&("restore"!=this.action||!this.hasCachedSnapshot())}cacheSnapshot(){this.snapshotCached||(this.view.cacheSnapshot(),this.snapshotCached=!0)}async render(e){this.cancelRender(),await new Promise((e=>{this.frame=requestAnimationFrame((()=>e()))})),await e(),delete this.frame,this.performScroll()}cancelRender(){this.frame&&(cancelAnimationFrame(this.frame),delete this.frame)}}function U(e){return e>=200&&e<300}class j{constructor(e){this.progressBar=new H,this.showProgressBar=()=>{this.progressBar.show()},this.session=e}visitProposedToLocation(e,t){this.navigator.startVisit(e,w(),t)}visitStarted(e){e.issueRequest(),e.changeHistory(),e.goToSamePageAnchor(),e.loadCachedSnapshot()}visitRequestStarted(e){this.progressBar.setValue(0),e.hasCachedSnapshot()||"restore"!=e.action?this.showVisitProgressBarAfterDelay():this.showProgressBar()}visitRequestCompleted(e){e.loadResponse()}visitRequestFailedWithStatusCode(e,t){switch(t){case V.networkFailure:case V.timeoutFailure:case V.contentTypeMismatch:return this.reload();default:return e.loadResponse()}}visitRequestFinished(e){this.progressBar.setValue(1),this.hideVisitProgressBar()}visitCompleted(e){}pageInvalidated(){this.reload()}visitFailed(e){}visitRendered(e){}formSubmissionStarted(e){this.progressBar.setValue(0),this.showFormProgressBarAfterDelay()}formSubmissionFinished(e){this.progressBar.setValue(1),this.hideFormProgressBar()}showVisitProgressBarAfterDelay(){this.visitProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay)}hideVisitProgressBar(){this.progressBar.hide(),null!=this.visitProgressBarTimeout&&(window.clearTimeout(this.visitProgressBarTimeout),delete this.visitProgressBarTimeout)}showFormProgressBarAfterDelay(){null==this.formProgressBarTimeout&&(this.formProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay))}hideFormProgressBar(){this.progressBar.hide(),null!=this.formProgressBarTimeout&&(window.clearTimeout(this.formProgressBarTimeout),delete this.formProgressBarTimeout)}reload(){window.location.reload()}get navigator(){return this.session.navigator}}class _{constructor(){this.started=!1}start(){this.started||(this.started=!0,addEventListener("turbo:before-cache",this.removeStaleElements,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-cache",this.removeStaleElements,!1))}removeStaleElements(){const e=[...document.querySelectorAll('[data-turbo-cache="false"]')];for(const t of e)t.remove()}}class ${constructor(e){this.started=!1,this.submitCaptured=()=>{removeEventListener("submit",this.submitBubbled,!1),addEventListener("submit",this.submitBubbled,!1)},this.submitBubbled=e=>{if(!e.defaultPrevented){const t=e.target instanceof HTMLFormElement?e.target:void 0,s=e.submitter||void 0;if(t){"dialog"!=((null==s?void 0:s.getAttribute("formmethod"))||t.method)&&this.delegate.willSubmitForm(t,s)&&(e.preventDefault(),this.delegate.formSubmitted(t,s))}}},this.delegate=e}start(){this.started||(addEventListener("submit",this.submitCaptured,!0),this.started=!0)}stop(){this.started&&(removeEventListener("submit",this.submitCaptured,!0),this.started=!1)}}class z{constructor(e){this.element=e,this.linkInterceptor=new I(this,e),this.formInterceptor=new P(this,e)}start(){this.linkInterceptor.start(),this.formInterceptor.start()}stop(){this.linkInterceptor.stop(),this.formInterceptor.stop()}shouldInterceptLinkClick(e,t){return this.shouldRedirect(e)}linkClickIntercepted(e,t){const s=this.findFrameElement(e);s&&(s.setAttribute("reloadable",""),s.src=t)}shouldInterceptFormSubmission(e,t){return this.shouldRedirect(e,t)}formSubmissionIntercepted(e,t){const s=this.findFrameElement(e,t);s&&(s.removeAttribute("reloadable"),s.delegate.formSubmissionIntercepted(e,t))}shouldRedirect(e,t){const s=this.findFrameElement(e,t);return!!s&&s!=e.closest("turbo-frame")}findFrameElement(e,t){const s=(null==t?void 0:t.getAttribute("data-turbo-frame"))||e.getAttribute("data-turbo-frame");if(s&&"_top"!=s){const e=this.element.querySelector(`#${s}:not([disabled])`);if(e instanceof c)return e}}}class J{constructor(e){this.restorationIdentifier=w(),this.restorationData={},this.started=!1,this.pageLoaded=!1,this.onPopState=e=>{if(this.shouldHandlePopState()){const{turbo:t}=e.state||{};if(t){this.location=new URL(window.location.href);const{restorationIdentifier:e}=t;this.restorationIdentifier=e,this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location,e)}}},this.onPageLoad=async e=>{await Promise.resolve(),this.pageLoaded=!0},this.delegate=e}start(){this.started||(addEventListener("popstate",this.onPopState,!1),addEventListener("load",this.onPageLoad,!1),this.started=!0,this.replace(new URL(window.location.href)))}stop(){this.started&&(removeEventListener("popstate",this.onPopState,!1),removeEventListener("load",this.onPageLoad,!1),this.started=!1)}push(e,t){this.update(history.pushState,e,t)}replace(e,t){this.update(history.replaceState,e,t)}update(e,t,s=w()){const i={turbo:{restorationIdentifier:s}};e.call(history,i,"",t.href),this.location=t,this.restorationIdentifier=s}getRestorationDataForIdentifier(e){return this.restorationData[e]||{}}updateRestorationData(e){const{restorationIdentifier:t}=this,s=this.restorationData[t];this.restorationData[t]=Object.assign(Object.assign({},s),e)}assumeControlOfScrollRestoration(){var e;this.previousScrollRestoration||(this.previousScrollRestoration=null!==(e=history.scrollRestoration)&&void 0!==e?e:"auto",history.scrollRestoration="manual")}relinquishControlOfScrollRestoration(){this.previousScrollRestoration&&(history.scrollRestoration=this.previousScrollRestoration,delete this.previousScrollRestoration)}shouldHandlePopState(){return this.pageIsLoaded()}pageIsLoaded(){return this.pageLoaded||"complete"==document.readyState}}class K{constructor(e){this.started=!1,this.clickCaptured=()=>{removeEventListener("click",this.clickBubbled,!1),addEventListener("click",this.clickBubbled,!1)},this.clickBubbled=e=>{if(this.clickEventIsSignificant(e)){const t=e.composedPath&&e.composedPath()[0]||e.target,s=this.findLinkFromClickTarget(t);if(s){const t=this.getLocationForLink(s);this.delegate.willFollowLinkToLocation(s,t)&&(e.preventDefault(),this.delegate.followedLinkToLocation(s,t))}}},this.delegate=e}start(){this.started||(addEventListener("click",this.clickCaptured,!0),this.started=!0)}stop(){this.started&&(removeEventListener("click",this.clickCaptured,!0),this.started=!1)}clickEventIsSignificant(e){return!(e.target&&e.target.isContentEditable||e.defaultPrevented||e.which>1||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey)}findLinkFromClickTarget(e){if(e instanceof Element)return e.closest("a[href]:not([target^=_]):not([download])")}getLocationForLink(e){return l(e.getAttribute("href")||"")}}function Q(e){return"advance"==e||"replace"==e||"restore"==e}class X{constructor(e){this.delegate=e}proposeVisit(e,t={}){this.delegate.allowsVisitingLocationWithAction(e,t.action)&&this.delegate.visitProposedToLocation(e,t)}startVisit(e,t,s={}){this.stop(),this.currentVisit=new x(this,l(e),t,Object.assign({referrer:this.location},s)),this.currentVisit.start()}submitForm(e,t){this.stop(),this.formSubmission=new C(this,e,t,!0),this.formSubmission.isIdempotent?this.proposeVisit(this.formSubmission.fetchRequest.url,{action:this.getActionForFormSubmission(this.formSubmission)}):this.formSubmission.start()}stop(){this.formSubmission&&(this.formSubmission.stop(),delete this.formSubmission),this.currentVisit&&(this.currentVisit.cancel(),delete this.currentVisit)}get adapter(){return this.delegate.adapter}get view(){return this.delegate.view}get history(){return this.delegate.history}formSubmissionStarted(e){"function"==typeof this.adapter.formSubmissionStarted&&this.adapter.formSubmissionStarted(e)}async formSubmissionSucceededWithResponse(e,t){if(e==this.formSubmission){const s=await t.responseHTML;if(s){e.method!=i.get&&this.view.clearSnapshotCache();const{statusCode:r}=t,n={response:{statusCode:r,responseHTML:s}};this.proposeVisit(t.location,n)}}}async formSubmissionFailedWithResponse(e,t){const s=await t.responseHTML;if(s){const e=D.fromHTMLString(s);t.serverError?await this.view.renderError(e):await this.view.renderPage(e),this.view.scrollToTop(),this.view.clearSnapshotCache()}}formSubmissionErrored(e,t){console.error(t)}formSubmissionFinished(e){"function"==typeof this.adapter.formSubmissionFinished&&this.adapter.formSubmissionFinished(e)}visitStarted(e){this.delegate.visitStarted(e)}visitCompleted(e){this.delegate.visitCompleted(e)}locationWithActionIsSamePage(e,t){const s=h(e),i=h(this.view.lastRenderedLocation),r="restore"===t&&void 0===s;return"replace"!==t&&m(e)===m(this.view.lastRenderedLocation)&&(r||null!=s&&s!==i)}visitScrolledToSamePageLocation(e,t){this.delegate.visitScrolledToSamePageLocation(e,t)}get location(){return this.history.location}get restorationIdentifier(){return this.history.restorationIdentifier}getActionForFormSubmission(e){const{formElement:t,submitter:s}=e,i=(null==s?void 0:s.getAttribute("data-turbo-action"))||t.getAttribute("data-turbo-action");return Q(i)?i:"advance"}}!function(e){e[e.initial=0]="initial",e[e.loading=1]="loading",e[e.interactive=2]="interactive",e[e.complete=3]="complete"}(N||(N={}));class Y{constructor(e){this.stage=N.initial,this.started=!1,this.interpretReadyState=()=>{const{readyState:e}=this;"interactive"==e?this.pageIsInteractive():"complete"==e&&this.pageIsComplete()},this.pageWillUnload=()=>{this.delegate.pageWillUnload()},this.delegate=e}start(){this.started||(this.stage==N.initial&&(this.stage=N.loading),document.addEventListener("readystatechange",this.interpretReadyState,!1),addEventListener("pagehide",this.pageWillUnload,!1),this.started=!0)}stop(){this.started&&(document.removeEventListener("readystatechange",this.interpretReadyState,!1),removeEventListener("pagehide",this.pageWillUnload,!1),this.started=!1)}pageIsInteractive(){this.stage==N.loading&&(this.stage=N.interactive,this.delegate.pageBecameInteractive())}pageIsComplete(){this.pageIsInteractive(),this.stage==N.interactive&&(this.stage=N.complete,this.delegate.pageLoaded())}get readyState(){return document.readyState}}class G{constructor(e){this.started=!1,this.onScroll=()=>{this.updatePosition({x:window.pageXOffset,y:window.pageYOffset})},this.delegate=e}start(){this.started||(addEventListener("scroll",this.onScroll,!1),this.onScroll(),this.started=!0)}stop(){this.started&&(removeEventListener("scroll",this.onScroll,!1),this.started=!1)}updatePosition(e){this.delegate.scrollPositionChanged(e)}}class Z{constructor(e){this.sources=new Set,this.started=!1,this.inspectFetchResponse=e=>{const t=function(e){var t;const s=null===(t=e.detail)||void 0===t?void 0:t.fetchResponse;if(s instanceof g)return s}(e);t&&function(e){var t;return(null!==(t=e.contentType)&&void 0!==t?t:"").startsWith(R.contentType)}(t)&&(e.preventDefault(),this.receiveMessageResponse(t))},this.receiveMessageEvent=e=>{this.started&&"string"==typeof e.data&&this.receiveMessageHTML(e.data)},this.delegate=e}start(){this.started||(this.started=!0,addEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}connectStreamSource(e){this.streamSourceIsConnected(e)||(this.sources.add(e),e.addEventListener("message",this.receiveMessageEvent,!1))}disconnectStreamSource(e){this.streamSourceIsConnected(e)&&(this.sources.delete(e),e.removeEventListener("message",this.receiveMessageEvent,!1))}streamSourceIsConnected(e){return this.sources.has(e)}async receiveMessageResponse(e){const t=await e.responseHTML;t&&this.receiveMessageHTML(t)}receiveMessageHTML(e){this.delegate.receivedMessageFromStream(new R(e))}}class ee extends F{async render(){this.replaceHeadAndBody(),this.activateScriptElements()}replaceHeadAndBody(){const{documentElement:e,head:t,body:s}=document;e.replaceChild(this.newHead,t),e.replaceChild(this.newElement,s)}activateScriptElements(){for(const e of this.scriptElements){const t=e.parentNode;if(t){const s=this.createScriptElement(e);t.replaceChild(s,e)}}}get newHead(){return this.newSnapshot.headSnapshot.element}get scriptElements(){return[...document.documentElement.querySelectorAll("script")]}}class te extends F{get shouldRender(){return this.newSnapshot.isVisitable&&this.trackedElementsAreIdentical}prepareToRender(){this.mergeHead()}async render(){this.replaceBody()}finishRendering(){super.finishRendering(),this.isPreview||this.focusFirstAutofocusableElement()}get currentHeadSnapshot(){return this.currentSnapshot.headSnapshot}get newHeadSnapshot(){return this.newSnapshot.headSnapshot}get newElement(){return this.newSnapshot.element}mergeHead(){this.copyNewHeadStylesheetElements(),this.copyNewHeadScriptElements(),this.removeCurrentHeadProvisionalElements(),this.copyNewHeadProvisionalElements()}replaceBody(){this.preservingPermanentElements((()=>{this.activateNewBody(),this.assignNewBody()}))}get trackedElementsAreIdentical(){return this.currentHeadSnapshot.trackedElementSignature==this.newHeadSnapshot.trackedElementSignature}copyNewHeadStylesheetElements(){for(const e of this.newHeadStylesheetElements)document.head.appendChild(e)}copyNewHeadScriptElements(){for(const e of this.newHeadScriptElements)document.head.appendChild(this.createScriptElement(e))}removeCurrentHeadProvisionalElements(){for(const e of this.currentHeadProvisionalElements)document.head.removeChild(e)}copyNewHeadProvisionalElements(){for(const e of this.newHeadProvisionalElements)document.head.appendChild(e)}activateNewBody(){document.adoptNode(this.newElement),this.activateNewBodyScriptElements()}activateNewBodyScriptElements(){for(const e of this.newBodyScriptElements){const t=this.createScriptElement(e);e.replaceWith(t)}}assignNewBody(){document.body&&this.newElement instanceof HTMLBodyElement?document.body.replaceWith(this.newElement):document.documentElement.appendChild(this.newElement)}get newHeadStylesheetElements(){return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot)}get newHeadScriptElements(){return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot)}get currentHeadProvisionalElements(){return this.currentHeadSnapshot.provisionalElements}get newHeadProvisionalElements(){return this.newHeadSnapshot.provisionalElements}get newBodyScriptElements(){return this.newElement.querySelectorAll("script")}}class se{constructor(e){this.keys=[],this.snapshots={},this.size=e}has(e){return p(e)in this.snapshots}get(e){if(this.has(e)){const t=this.read(e);return this.touch(e),t}}put(e,t){return this.write(e,t),this.touch(e),t}clear(){this.snapshots={}}read(e){return this.snapshots[p(e)]}write(e,t){this.snapshots[p(e)]=t}touch(e){const t=p(e),s=this.keys.indexOf(t);s>-1&&this.keys.splice(s,1),this.keys.unshift(t),this.trim()}trim(){for(const e of this.keys.splice(this.size))delete this.snapshots[e]}}class ie extends T{constructor(){super(...arguments),this.snapshotCache=new se(10),this.lastRenderedLocation=new URL(location.href)}renderPage(e,t=!1){const s=new te(this.snapshot,e,t);return this.render(s)}renderError(e){const t=new ee(this.snapshot,e,!1);return this.render(t)}clearSnapshotCache(){this.snapshotCache.clear()}async cacheSnapshot(){if(this.shouldCacheSnapshot){this.delegate.viewWillCacheSnapshot();const{snapshot:e,lastRenderedLocation:t}=this;await new Promise((e=>setTimeout((()=>e()),0))),this.snapshotCache.put(t,e.clone())}}getCachedSnapshotForLocation(e){return this.snapshotCache.get(e)}get snapshot(){return D.fromElement(this.element)}get shouldCacheSnapshot(){return this.snapshot.isCacheable}}function re(e){Object.defineProperties(e,ne)}const ne={absoluteURL:{get(){return this.toString()}}},oe=new class{constructor(){this.navigator=new X(this),this.history=new J(this),this.view=new ie(this,document.documentElement),this.adapter=new j(this),this.pageObserver=new Y(this),this.cacheObserver=new _,this.linkClickObserver=new K(this),this.formSubmitObserver=new $(this),this.scrollObserver=new G(this),this.streamObserver=new Z(this),this.frameRedirector=new z(document.documentElement),this.drive=!0,this.enabled=!0,this.progressBarDelay=500,this.started=!1}start(){this.started||(this.pageObserver.start(),this.cacheObserver.start(),this.linkClickObserver.start(),this.formSubmitObserver.start(),this.scrollObserver.start(),this.streamObserver.start(),this.frameRedirector.start(),this.history.start(),this.started=!0,this.enabled=!0)}disable(){this.enabled=!1}stop(){this.started&&(this.pageObserver.stop(),this.cacheObserver.stop(),this.linkClickObserver.stop(),this.formSubmitObserver.stop(),this.scrollObserver.stop(),this.streamObserver.stop(),this.frameRedirector.stop(),this.history.stop(),this.started=!1)}registerAdapter(e){this.adapter=e}visit(e,t={}){this.navigator.proposeVisit(l(e),t)}connectStreamSource(e){this.streamObserver.connectStreamSource(e)}disconnectStreamSource(e){this.streamObserver.disconnectStreamSource(e)}renderStreamMessage(e){document.documentElement.appendChild(R.wrap(e).fragment)}clearCache(){this.view.clearSnapshotCache()}setProgressBarDelay(e){this.progressBarDelay=e}get location(){return this.history.location}get restorationIdentifier(){return this.history.restorationIdentifier}historyPoppedToLocationWithRestorationIdentifier(e,t){this.enabled?this.navigator.startVisit(e,t,{action:"restore",historyChanged:!0}):this.adapter.pageInvalidated()}scrollPositionChanged(e){this.history.updateRestorationData({scrollPosition:e})}willFollowLinkToLocation(e,t){return this.elementDriveEnabled(e)&&this.locationIsVisitable(t)&&this.applicationAllowsFollowingLinkToLocation(e,t)}followedLinkToLocation(e,t){const s=this.getActionForLink(e);this.convertLinkWithMethodClickToFormSubmission(e)||this.visit(t.href,{action:s})}convertLinkWithMethodClickToFormSubmission(e){var t;const s=e.getAttribute("data-turbo-method");if(s){const i=document.createElement("form");return i.method=s,i.action=e.getAttribute("href")||"undefined",i.hidden=!0,null===(t=e.parentNode)||void 0===t||t.insertBefore(i,e),f("submit",{cancelable:!0,target:i})}return!1}allowsVisitingLocationWithAction(e,t){return this.locationWithActionIsSamePage(e,t)||this.applicationAllowsVisitingLocation(e)}visitProposedToLocation(e,t){re(e),this.adapter.visitProposedToLocation(e,t)}visitStarted(e){re(e.location),e.silent||this.notifyApplicationAfterVisitingLocation(e.location,e.action)}visitCompleted(e){this.notifyApplicationAfterPageLoad(e.getTimingMetrics())}locationWithActionIsSamePage(e,t){return this.navigator.locationWithActionIsSamePage(e,t)}visitScrolledToSamePageLocation(e,t){this.notifyApplicationAfterVisitingSamePageLocation(e,t)}willSubmitForm(e,t){return this.elementDriveEnabled(e)&&(!t||this.elementDriveEnabled(t))}formSubmitted(e,t){this.navigator.submitForm(e,t)}pageBecameInteractive(){this.view.lastRenderedLocation=this.location,this.notifyApplicationAfterPageLoad()}pageLoaded(){this.history.assumeControlOfScrollRestoration()}pageWillUnload(){this.history.relinquishControlOfScrollRestoration()}receivedMessageFromStream(e){this.renderStreamMessage(e)}viewWillCacheSnapshot(){var e;(null===(e=this.navigator.currentVisit)||void 0===e?void 0:e.silent)||this.notifyApplicationBeforeCachingSnapshot()}allowsImmediateRender({element:e},t){return!this.notifyApplicationBeforeRender(e,t).defaultPrevented}viewRenderedSnapshot(e,t){this.view.lastRenderedLocation=this.history.location,this.notifyApplicationAfterRender()}viewInvalidated(){this.adapter.pageInvalidated()}frameLoaded(e){this.notifyApplicationAfterFrameLoad(e)}frameRendered(e,t){this.notifyApplicationAfterFrameRender(e,t)}applicationAllowsFollowingLinkToLocation(e,t){return!this.notifyApplicationAfterClickingLinkToLocation(e,t).defaultPrevented}applicationAllowsVisitingLocation(e){return!this.notifyApplicationBeforeVisitingLocation(e).defaultPrevented}notifyApplicationAfterClickingLinkToLocation(e,t){return f("turbo:click",{target:e,detail:{url:t.href},cancelable:!0})}notifyApplicationBeforeVisitingLocation(e){return f("turbo:before-visit",{detail:{url:e.href},cancelable:!0})}notifyApplicationAfterVisitingLocation(e,t){return f("turbo:visit",{detail:{url:e.href,action:t}})}notifyApplicationBeforeCachingSnapshot(){return f("turbo:before-cache")}notifyApplicationBeforeRender(e,t){return f("turbo:before-render",{detail:{newBody:e,resume:t},cancelable:!0})}notifyApplicationAfterRender(){return f("turbo:render")}notifyApplicationAfterPageLoad(e={}){return f("turbo:load",{detail:{url:this.location.href,timing:e}})}notifyApplicationAfterVisitingSamePageLocation(e,t){dispatchEvent(new HashChangeEvent("hashchange",{oldURL:e.toString(),newURL:t.toString()}))}notifyApplicationAfterFrameLoad(e){return f("turbo:frame-load",{target:e})}notifyApplicationAfterFrameRender(e,t){return f("turbo:frame-render",{detail:{fetchResponse:e},target:t,cancelable:!0})}elementDriveEnabled(e){const t=null==e?void 0:e.closest("[data-turbo]");return this.drive?!t||"false"!=t.getAttribute("data-turbo"):!!t&&"true"==t.getAttribute("data-turbo")}getActionForLink(e){const t=e.getAttribute("data-turbo-action");return Q(t)?t:"advance"}locationIsVisitable(e){return u(e,this.snapshot.rootLocation)&&!!d(e).match(/^(?:|\.(?:htm|html|xhtml))$/)}get snapshot(){return this.view.snapshot}},{navigator:ae}=oe;function ce(){oe.start()}function le(e){oe.registerAdapter(e)}function he(e,t){oe.visit(e,t)}function de(e){oe.connectStreamSource(e)}function ue(e){oe.disconnectStreamSource(e)}function me(e){oe.renderStreamMessage(e)}function pe(){oe.clearCache()}function ge(e){oe.setProgressBarDelay(e)}var fe=Object.freeze({__proto__:null,navigator:ae,session:oe,PageRenderer:te,PageSnapshot:D,start:ce,registerAdapter:le,visit:he,connectStreamSource:de,disconnectStreamSource:ue,renderStreamMessage:me,clearCache:pe,setProgressBarDelay:ge});function ve(e){if(null!=e){const t=document.getElementById(e);if(t instanceof c)return t}}function be(e,t){if(e){const i=e.getAttribute("src");if(null!=i&&null!=t&&(s=t,l(i).href==l(s).href))throw new Error(`Matching <turbo-frame id="${e.id}"> element has a source URL which references itself`);if(e.ownerDocument!==document&&(e=document.importNode(e,!0)),e instanceof c)return e.connectedCallback(),e}var s}const Se={after(){this.targetElements.forEach((e=>{var t;return null===(t=e.parentElement)||void 0===t?void 0:t.insertBefore(this.templateContent,e.nextSibling)}))},append(){this.removeDuplicateTargetChildren(),this.targetElements.forEach((e=>e.append(this.templateContent)))},before(){this.targetElements.forEach((e=>{var t;return null===(t=e.parentElement)||void 0===t?void 0:t.insertBefore(this.templateContent,e)}))},prepend(){this.removeDuplicateTargetChildren(),this.targetElements.forEach((e=>e.prepend(this.templateContent)))},remove(){this.targetElements.forEach((e=>e.remove()))},replace(){this.targetElements.forEach((e=>e.replaceWith(this.templateContent)))},update(){this.targetElements.forEach((e=>{e.innerHTML="",e.append(this.templateContent)}))}};class we extends HTMLElement{async connectedCallback(){try{await this.render()}catch(e){console.error(e)}finally{this.disconnect()}}async render(){var e;return null!==(e=this.renderPromise)&&void 0!==e?e:this.renderPromise=(async()=>{this.dispatchEvent(this.beforeRenderEvent)&&(await v(),this.performAction())})()}disconnect(){try{this.remove()}catch(e){}}removeDuplicateTargetChildren(){this.duplicateChildren.forEach((e=>e.remove()))}get duplicateChildren(){var e;const t=this.targetElements.flatMap((e=>[...e.children])).filter((e=>!!e.id)),s=[...null===(e=this.templateContent)||void 0===e?void 0:e.children].filter((e=>!!e.id)).map((e=>e.id));return t.filter((e=>s.includes(e.id)))}get performAction(){if(this.action){const e=Se[this.action];if(e)return e;this.raise("unknown action")}this.raise("action attribute is missing")}get targetElements(){return this.target?this.targetElementsById:this.targets?this.targetElementsByQuery:void this.raise("target or targets attribute is missing")}get templateContent(){return this.templateElement.content.cloneNode(!0)}get templateElement(){if(this.firstElementChild instanceof HTMLTemplateElement)return this.firstElementChild;this.raise("first child element must be a <template> element")}get action(){return this.getAttribute("action")}get target(){return this.getAttribute("target")}get targets(){return this.getAttribute("targets")}raise(e){throw new Error(`${this.description}: ${e}`)}get description(){var e,t;return null!==(t=(null!==(e=this.outerHTML.match(/<[^>]+>/))&&void 0!==e?e:[])[0])&&void 0!==t?t:"<turbo-stream>"}get beforeRenderEvent(){return new CustomEvent("turbo:before-stream-render",{bubbles:!0,cancelable:!0})}get targetElementsById(){var e;const t=null===(e=this.ownerDocument)||void 0===e?void 0:e.getElementById(this.target);return null!==t?[t]:[]}get targetElementsByQuery(){var e;const t=null===(e=this.ownerDocument)||void 0===e?void 0:e.querySelectorAll(this.targets);return 0!==t.length?Array.prototype.slice.call(t):[]}}c.delegateConstructor=class{constructor(e){this.resolveVisitPromise=()=>{},this.connected=!1,this.hasBeenLoaded=!1,this.settingSourceURL=!1,this.element=e,this.view=new k(this,this.element),this.appearanceObserver=new E(this,this.element),this.linkInterceptor=new I(this,this.element),this.formInterceptor=new P(this,this.element)}connect(){this.connected||(this.connected=!0,this.reloadable=!1,this.loadingStyle==s.lazy&&this.appearanceObserver.start(),this.linkInterceptor.start(),this.formInterceptor.start(),this.sourceURLChanged())}disconnect(){this.connected&&(this.connected=!1,this.appearanceObserver.stop(),this.linkInterceptor.stop(),this.formInterceptor.stop())}disabledChanged(){this.loadingStyle==s.eager&&this.loadSourceURL()}sourceURLChanged(){(this.loadingStyle==s.eager||this.hasBeenLoaded)&&this.loadSourceURL()}loadingStyleChanged(){this.loadingStyle==s.lazy?this.appearanceObserver.start():(this.appearanceObserver.stop(),this.loadSourceURL())}async loadSourceURL(){if(!this.settingSourceURL&&this.enabled&&this.isActive&&(this.reloadable||this.sourceURL!=this.currentURL)){const e=this.currentURL;if(this.currentURL=this.sourceURL,this.sourceURL)try{this.element.loaded=this.visit(this.sourceURL),this.appearanceObserver.stop(),await this.element.loaded,this.hasBeenLoaded=!0,oe.frameLoaded(this.element)}catch(t){throw this.currentURL=e,t}}}async loadResponse(e){e.redirected&&(this.sourceURL=e.response.url);try{const t=await e.responseHTML;if(t){const{body:s}=b(t),i=new A(await this.extractForeignFrameElement(s)),r=new M(this.view.snapshot,i,!1);this.view.renderPromise&&await this.view.renderPromise,await this.view.render(r),oe.frameRendered(e,this.element)}}catch(e){console.error(e),this.view.invalidate()}}elementAppearedInViewport(e){this.loadSourceURL()}shouldInterceptLinkClick(e,t){return!e.hasAttribute("data-turbo-method")&&this.shouldInterceptNavigation(e)}linkClickIntercepted(e,t){this.reloadable=!0,this.navigateFrame(e,t)}shouldInterceptFormSubmission(e,t){return this.shouldInterceptNavigation(e,t)}formSubmissionIntercepted(e,t){if(this.formSubmission&&this.formSubmission.stop(),this.reloadable=!1,this.formSubmission=new C(this,e,t),this.formSubmission.fetchRequest.isIdempotent)this.navigateFrame(e,this.formSubmission.fetchRequest.url.href,t);else{const{fetchRequest:e}=this.formSubmission;this.prepareHeadersForRequest(e.headers,e),this.formSubmission.start()}}prepareHeadersForRequest(e,t){e["Turbo-Frame"]=this.id}requestStarted(e){this.element.setAttribute("busy","")}requestPreventedHandlingResponse(e,t){this.resolveVisitPromise()}async requestSucceededWithResponse(e,t){await this.loadResponse(t),this.resolveVisitPromise()}requestFailedWithResponse(e,t){console.error(t),this.resolveVisitPromise()}requestErrored(e,t){console.error(t),this.resolveVisitPromise()}requestFinished(e){this.element.removeAttribute("busy")}formSubmissionStarted(e){this.findFrameElement(e.formElement).setAttribute("busy","")}formSubmissionSucceededWithResponse(e,t){this.findFrameElement(e.formElement,e.submitter).delegate.loadResponse(t)}formSubmissionFailedWithResponse(e,t){this.element.delegate.loadResponse(t)}formSubmissionErrored(e,t){console.error(t)}formSubmissionFinished(e){this.findFrameElement(e.formElement).removeAttribute("busy")}allowsImmediateRender(e,t){return!0}viewRenderedSnapshot(e,t){}viewInvalidated(){}async visit(e){const t=new y(this,i.get,l(e),void 0,this.element);return new Promise((e=>{this.resolveVisitPromise=()=>{this.resolveVisitPromise=()=>{},e()},t.perform()}))}navigateFrame(e,t,s){const i=this.findFrameElement(e,s);i.setAttribute("reloadable",""),i.src=t}findFrameElement(e,t){var s;return null!==(s=ve((null==t?void 0:t.getAttribute("data-turbo-frame"))||e.getAttribute("data-turbo-frame")||this.element.getAttribute("target")))&&void 0!==s?s:this.element}async extractForeignFrameElement(e){let t;const s=CSS.escape(this.id);try{if(t=be(e.querySelector(`turbo-frame#${s}`),this.currentURL))return t;if(t=be(e.querySelector(`turbo-frame[src][recurse~=${s}]`),this.currentURL))return await t.loaded,await this.extractForeignFrameElement(t);console.error(`Response has no matching <turbo-frame id="${s}"> element`)}catch(e){console.error(e)}return new c}shouldInterceptNavigation(e,t){const s=(null==t?void 0:t.getAttribute("data-turbo-frame"))||e.getAttribute("data-turbo-frame")||this.element.getAttribute("target");if(!this.enabled||"_top"==s)return!1;if(s){const e=ve(s);if(e)return!e.disabled}return!!oe.elementDriveEnabled(e)&&!(t&&!oe.elementDriveEnabled(t))}get id(){return this.element.id}get enabled(){return!this.element.disabled}get sourceURL(){if(this.element.src)return this.element.src}get reloadable(){return this.findFrameElement(this.element).hasAttribute("reloadable")}set reloadable(e){const t=this.findFrameElement(this.element);e?t.setAttribute("reloadable",""):t.removeAttribute("reloadable")}set sourceURL(e){this.settingSourceURL=!0,this.element.src=null!=e?e:null,this.currentURL=this.element.src,this.settingSourceURL=!1}get loadingStyle(){return this.element.loading}get isLoading(){return void 0!==this.formSubmission||void 0!==this.resolveVisitPromise()}get isActive(){return this.element.isActive&&this.connected}},customElements.define("turbo-frame",c),customElements.define("turbo-stream",we),(()=>{let e=document.currentScript;if(e&&!e.hasAttribute("data-turbo-suppress-warning"))for(;e=e.parentElement;)if(e==document.body)return console.warn(S`
16
+ You are loading Turbo from a <script> element inside the <body> element. This is probably not what you meant to do!
17
+
18
+ Load your application’s JavaScript bundle inside the <head> element instead. <script> elements in <body> are evaluated with each page change.
19
+
20
+ For more information, see: https://turbo.hotwired.dev/handbook/building#working-with-script-elements
21
+
22
+ ——
23
+ Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
24
+ `,e.outerHTML)})(),window.Turbo=fe,ce();var ye=Object.freeze({__proto__:null,PageRenderer:te,PageSnapshot:D,clearCache:pe,connectStreamSource:de,disconnectStreamSource:ue,navigator:ae,registerAdapter:le,renderStreamMessage:me,session:oe,setProgressBarDelay:ge,start:ce,visit:he});let Ee;async function Re(){return Ee||Ce(Le().then(Ce))}function Ce(e){return Ee=e}async function Le(){const{createConsumer:e}=await Promise.resolve().then((function(){return $e}));return e()}async function Ae(e,t){const{subscriptions:s}=await Re();return s.create(e,t)}var Pe=Object.freeze({__proto__:null,getConsumer:Re,setConsumer:Ce,createConsumer:Le,subscribeTo:Ae});class Te extends HTMLElement{async connectedCallback(){de(this),this.subscription=await Ae(this.channel,{received:this.dispatchMessageEvent.bind(this)})}disconnectedCallback(){ue(this),this.subscription&&this.subscription.unsubscribe()}dispatchMessageEvent(e){const t=new MessageEvent("message",{data:e});return this.dispatchEvent(t)}get channel(){return{channel:this.getAttribute("channel"),signed_stream_name:this.getAttribute("signed-stream-name")}}}customElements.define("turbo-cable-stream-source",Te);var ke={logger:self.console,WebSocket:self.WebSocket},Ie={log(...e){this.enabled&&(e.push(Date.now()),ke.logger.log("[ActionCable]",...e))}};const Fe=()=>(new Date).getTime(),Me=e=>(Fe()-e)/1e3;class He{constructor(e){this.visibilityDidChange=this.visibilityDidChange.bind(this),this.connection=e,this.reconnectAttempts=0}start(){this.isRunning()||(this.startedAt=Fe(),delete this.stoppedAt,this.startPolling(),addEventListener("visibilitychange",this.visibilityDidChange),Ie.log(`ConnectionMonitor started. pollInterval = ${this.getPollInterval()} ms`))}stop(){this.isRunning()&&(this.stoppedAt=Fe(),this.stopPolling(),removeEventListener("visibilitychange",this.visibilityDidChange),Ie.log("ConnectionMonitor stopped"))}isRunning(){return this.startedAt&&!this.stoppedAt}recordPing(){this.pingedAt=Fe()}recordConnect(){this.reconnectAttempts=0,this.recordPing(),delete this.disconnectedAt,Ie.log("ConnectionMonitor recorded connect")}recordDisconnect(){this.disconnectedAt=Fe(),Ie.log("ConnectionMonitor recorded disconnect")}startPolling(){this.stopPolling(),this.poll()}stopPolling(){clearTimeout(this.pollTimeout)}poll(){this.pollTimeout=setTimeout((()=>{this.reconnectIfStale(),this.poll()}),this.getPollInterval())}getPollInterval(){const{min:e,max:t,multiplier:s}=this.constructor.pollInterval,i=s*Math.log(this.reconnectAttempts+1);return Math.round(1e3*((e,t,s)=>Math.max(t,Math.min(s,e)))(i,e,t))}reconnectIfStale(){this.connectionIsStale()&&(Ie.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, pollInterval = ${this.getPollInterval()} ms, time disconnected = ${Me(this.disconnectedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`),this.reconnectAttempts++,this.disconnectedRecently()?Ie.log("ConnectionMonitor skipping reopening recent disconnect"):(Ie.log("ConnectionMonitor reopening"),this.connection.reopen()))}connectionIsStale(){return Me(this.pingedAt?this.pingedAt:this.startedAt)>this.constructor.staleThreshold}disconnectedRecently(){return this.disconnectedAt&&Me(this.disconnectedAt)<this.constructor.staleThreshold}visibilityDidChange(){"visible"===document.visibilityState&&setTimeout((()=>{!this.connectionIsStale()&&this.connection.isOpen()||(Ie.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`),this.connection.reopen())}),200)}}He.pollInterval={min:3,max:30,multiplier:5},He.staleThreshold=6;var Be={message_types:{welcome:"welcome",disconnect:"disconnect",ping:"ping",confirmation:"confirm_subscription",rejection:"reject_subscription"},disconnect_reasons:{unauthorized:"unauthorized",invalid_request:"invalid_request",server_restart:"server_restart"},default_mount_path:"/cable",protocols:["actioncable-v1-json","actioncable-unsupported"]};const{message_types:qe,protocols:Oe}=Be,De=Oe.slice(0,Oe.length-1),We=[].indexOf;class Ve{constructor(e){this.open=this.open.bind(this),this.consumer=e,this.subscriptions=this.consumer.subscriptions,this.monitor=new He(this),this.disconnected=!0}send(e){return!!this.isOpen()&&(this.webSocket.send(JSON.stringify(e)),!0)}open(){return this.isActive()?(Ie.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`),!1):(Ie.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${Oe}`),this.webSocket&&this.uninstallEventHandlers(),this.webSocket=new ke.WebSocket(this.consumer.url,Oe),this.installEventHandlers(),this.monitor.start(),!0)}close({allowReconnect:e}={allowReconnect:!0}){if(e||this.monitor.stop(),this.isActive())return this.webSocket.close()}reopen(){if(Ie.log(`Reopening WebSocket, current state is ${this.getState()}`),!this.isActive())return this.open();try{return this.close()}catch(e){Ie.log("Failed to reopen WebSocket",e)}finally{Ie.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`),setTimeout(this.open,this.constructor.reopenDelay)}}getProtocol(){if(this.webSocket)return this.webSocket.protocol}isOpen(){return this.isState("open")}isActive(){return this.isState("open","connecting")}isProtocolSupported(){return We.call(De,this.getProtocol())>=0}isState(...e){return We.call(e,this.getState())>=0}getState(){if(this.webSocket)for(let e in ke.WebSocket)if(ke.WebSocket[e]===this.webSocket.readyState)return e.toLowerCase();return null}installEventHandlers(){for(let e in this.events){const t=this.events[e].bind(this);this.webSocket[`on${e}`]=t}}uninstallEventHandlers(){for(let e in this.events)this.webSocket[`on${e}`]=function(){}}}Ve.reopenDelay=500,Ve.prototype.events={message(e){if(!this.isProtocolSupported())return;const{identifier:t,message:s,reason:i,reconnect:r,type:n}=JSON.parse(e.data);switch(n){case qe.welcome:return this.monitor.recordConnect(),this.subscriptions.reload();case qe.disconnect:return Ie.log(`Disconnecting. Reason: ${i}`),this.close({allowReconnect:r});case qe.ping:return this.monitor.recordPing();case qe.confirmation:return this.subscriptions.notify(t,"connected");case qe.rejection:return this.subscriptions.reject(t);default:return this.subscriptions.notify(t,"received",s)}},open(){if(Ie.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`),this.disconnected=!1,!this.isProtocolSupported())return Ie.log("Protocol is unsupported. Stopping monitor and disconnecting."),this.close({allowReconnect:!1})},close(e){if(Ie.log("WebSocket onclose event"),!this.disconnected)return this.disconnected=!0,this.monitor.recordDisconnect(),this.subscriptions.notifyAll("disconnected",{willAttemptReconnect:this.monitor.isRunning()})},error(){Ie.log("WebSocket onerror event")}};class Ne{constructor(e,t={},s){this.consumer=e,this.identifier=JSON.stringify(t),function(e,t){if(null!=t)for(let s in t){const i=t[s];e[s]=i}}(this,s)}perform(e,t={}){return t.action=e,this.send(t)}send(e){return this.consumer.send({command:"message",identifier:this.identifier,data:JSON.stringify(e)})}unsubscribe(){return this.consumer.subscriptions.remove(this)}}class xe{constructor(e){this.consumer=e,this.subscriptions=[]}create(e,t){const s="object"==typeof e?e:{channel:e},i=new Ne(this.consumer,s,t);return this.add(i)}add(e){return this.subscriptions.push(e),this.consumer.ensureActiveConnection(),this.notify(e,"initialized"),this.sendCommand(e,"subscribe"),e}remove(e){return this.forget(e),this.findAll(e.identifier).length||this.sendCommand(e,"unsubscribe"),e}reject(e){return this.findAll(e).map((e=>(this.forget(e),this.notify(e,"rejected"),e)))}forget(e){return this.subscriptions=this.subscriptions.filter((t=>t!==e)),e}findAll(e){return this.subscriptions.filter((t=>t.identifier===e))}reload(){return this.subscriptions.map((e=>this.sendCommand(e,"subscribe")))}notifyAll(e,...t){return this.subscriptions.map((s=>this.notify(s,e,...t)))}notify(e,t,...s){let i;return i="string"==typeof e?this.findAll(e):[e],i.map((e=>"function"==typeof e[t]?e[t](...s):void 0))}sendCommand(e,t){const{identifier:s}=e;return this.consumer.send({command:t,identifier:s})}}class Ue{constructor(e){this._url=e,this.subscriptions=new xe(this),this.connection=new Ve(this)}get url(){return je(this._url)}send(e){return this.connection.send(e)}connect(){return this.connection.open()}disconnect(){return this.connection.close({allowReconnect:!1})}ensureActiveConnection(){if(!this.connection.isActive())return this.connection.open()}}function je(e){if("function"==typeof e&&(e=e()),e&&!/^wss?:/i.test(e)){const t=document.createElement("a");return t.href=e,t.href=t.href,t.protocol=t.protocol.replace("http","ws"),t.href}return e}function _e(e){const t=document.head.querySelector(`meta[name='action-cable-${e}']`);if(t)return t.getAttribute("content")}var $e=Object.freeze({__proto__:null,Connection:Ve,ConnectionMonitor:He,Consumer:Ue,INTERNAL:Be,Subscription:Ne,Subscriptions:xe,adapters:ke,createWebSocketURL:je,logger:Ie,createConsumer:function(e=_e("url")||Be.default_mount_path){return new Ue(e)},getConfig:_e});export{ye as Turbo,Pe as cable};
@@ -13,6 +13,13 @@ module Turbo::Streams::StreamName
13
13
  Turbo.signed_stream_verifier.generate stream_name_from(streamables)
14
14
  end
15
15
 
16
+ module ClassMethods
17
+ # Can be used by custom turbo stream channels to obtain signed stream name from <tt>params</tt>
18
+ def verified_stream_name_from_params
19
+ self.class.verified_stream_name(params[:signed_stream_name])
20
+ end
21
+ end
22
+
16
23
  private
17
24
  def stream_name_from(streamables)
18
25
  if streamables.is_a?(Array)
@@ -4,12 +4,40 @@
4
4
  # into signed stream name using <tt>Turbo::Streams::StreamName#signed_stream_name</tt>. This is automatically done
5
5
  # using the view helper <tt>Turbo::StreamsHelper#turbo_stream_from(*streamables)</tt>.
6
6
  # If the signed stream name cannot be verified, the subscription is rejected.
7
+ #
8
+ # In case if custom behavior is desired, one can create their own channel and re-use some of the primitives from
9
+ # helper modules like <tt>Turbo::Streams::StreamName</tt>:
10
+ #
11
+ # class CustomChannel < ActionCable::Channel::Base
12
+ # extend Turbo::Stream::Broadcasts, Turbo::Streams::StreamName
13
+ # include Turbo::Streams::StreamName::ClassMethods
14
+ #
15
+ # def subscribed
16
+ # if (stream_name = verified_stream_name_from_params).present? &&
17
+ # subscription_allowed?
18
+ # stream_from stream_name
19
+ # else
20
+ # reject
21
+ # end
22
+ # end
23
+ #
24
+ # def subscription_allowed?
25
+ # # ...
26
+ # end
27
+ # end
28
+ #
29
+ # This channel can be connected to a web page using <tt>:channel</tt> option in
30
+ # <tt>turbo_stream_from</tt> helper:
31
+ #
32
+ # <%= turbo_stream_from 'room', channel: CustomChannel %>
33
+ #
7
34
  class Turbo::StreamsChannel < ActionCable::Channel::Base
8
35
  extend Turbo::Streams::Broadcasts, Turbo::Streams::StreamName
36
+ include Turbo::Streams::StreamName::ClassMethods
9
37
 
10
38
  def subscribed
11
- if verified_stream_name = self.class.verified_stream_name(params[:signed_stream_name])
12
- stream_from verified_stream_name
39
+ if stream_name = verified_stream_name_from_params
40
+ stream_from stream_name
13
41
  else
14
42
  reject
15
43
  end
@@ -19,6 +19,10 @@ module Turbo::Frames::FrameRequest
19
19
 
20
20
  private
21
21
  def turbo_frame_request?
22
- request.headers["Turbo-Frame"].present?
22
+ turbo_frame_request_id.present?
23
+ end
24
+
25
+ def turbo_frame_request_id
26
+ request.headers["Turbo-Frame"]
23
27
  end
24
28
  end
@@ -39,9 +39,15 @@ module Turbo::StreamsHelper
39
39
  # The example above will process all turbo streams sent to a stream name like <tt>account:5:entries</tt>
40
40
  # (when Current.account.id = 5). Updates to this stream can be sent like
41
41
  # <tt>entry.broadcast_append_to entry.account, :entries, target: "entries"</tt>.
42
+ #
43
+ # Custom channel class name can be passed using <tt>:channel</tt> option (either as a String
44
+ # or a class name):
45
+ #
46
+ # <%= turbo_stream_from "room", channel: RoomChannel %>
42
47
  def turbo_stream_from(*streamables, **attributes)
43
- attributes[:channel] = "Turbo::StreamsChannel"
48
+ attributes[:channel] = attributes[:channel]&.to_s || "Turbo::StreamsChannel"
44
49
  attributes[:"signed-stream-name"] = Turbo::StreamsChannel.signed_stream_name(streamables)
50
+
45
51
  tag.turbo_cable_stream_source(**attributes)
46
52
  end
47
53
  end
@@ -26,6 +26,20 @@
26
26
  # and finally prepend the result of that partial rendering to the target identified with the dom id "clearances"
27
27
  # (which is derived by default from the plural model name of the model, but can be overwritten).
28
28
  #
29
+ # You can also choose to render html instead of a partial inside of a broadcast
30
+ # you do this by passing the html: option to any broadcast method that accepts the **rendering argument
31
+ #
32
+ # class Message < ApplicationRecord
33
+ # belongs_to :user
34
+ #
35
+ # after_create_commit :update_message_count
36
+ #
37
+ # private
38
+ # def update_message_count
39
+ # broadcast_update_to(user, :messages, target: "message-count", html: "<p> #{user.messages.count} </p>")
40
+ # end
41
+ # end
42
+ #
29
43
  # There are four basic actions you can broadcast: <tt>remove</tt>, <tt>replace</tt>, <tt>append</tt>, and
30
44
  # <tt>prepend</tt>. As a rule, you should use the <tt>_later</tt> versions of everything except for remove when broadcasting
31
45
  # within a real-time path, like a controller or model, since all those updates require a rendering step, which can slow down
@@ -297,7 +311,10 @@ module Turbo::Broadcastable
297
311
  # Add the current instance into the locals with the element name (which is the un-namespaced name)
298
312
  # as the key. This parallels how the ActionView::ObjectRenderer would create a local variable.
299
313
  o[:locals] = (o[:locals] || {}).reverse_merge!(model_name.element.to_sym => self)
300
- o[:partial] ||= to_partial_path
314
+ # if the html option is passed in it will skip setting a partial from #to_partial_path
315
+ unless o.include?(:html)
316
+ o[:partial] ||= to_partial_path
317
+ end
301
318
  end
302
319
  end
303
320
  end
@@ -7,7 +7,8 @@ if (cable_config_path = Rails.root.join("config/cable.yml")).exist?
7
7
  if gemfile_content.match?(pattern)
8
8
  uncomment_lines "Gemfile", pattern
9
9
  else
10
- gem 'redis', '~> 4.0', comment: "Use Redis as Action Cable adapter instead of default Async. The Async adapter\ndoes not support Turbo Stream broadcasting."
10
+ append_file "Gemfile", "\n# Use Redis for Action Cable"
11
+ gem 'redis', '~> 4.0'
11
12
  end
12
13
 
13
14
  run_bundle
data/lib/turbo/engine.rb CHANGED
@@ -20,9 +20,17 @@ module Turbo
20
20
  Rails.autoloaders.once.do_not_eager_load(Dir["#{root}/app/channels/turbo/*_channel.rb"]) unless defined?(ActionCable)
21
21
  end
22
22
 
23
+ # If you don't want to precompile Turbo's assets (eg. because you're using webpack),
24
+ # you can do this in an intiailzer:
25
+ #
26
+ # config.after_initialize do
27
+ # config.assets.precompile -= Turbo::Engine::PRECOMPILE_ASSETS
28
+ # end
29
+ PRECOMPILE_ASSETS = %w( turbo.js turbo.min.js )
30
+
23
31
  initializer "turbo.assets" do
24
32
  if Rails.application.config.respond_to?(:assets)
25
- Rails.application.config.assets.precompile += %w( turbo.js )
33
+ Rails.application.config.assets.precompile += PRECOMPILE_ASSETS
26
34
  end
27
35
  end
28
36
 
data/lib/turbo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Turbo
2
- VERSION = "0.8.1"
2
+ VERSION = "0.8.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-09-25 00:00:00.000000000 Z
13
+ date: 2021-11-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -36,6 +36,7 @@ files:
36
36
  - README.md
37
37
  - Rakefile
38
38
  - app/assets/javascripts/turbo.js
39
+ - app/assets/javascripts/turbo.min.js
39
40
  - app/channels/turbo/streams/broadcasts.rb
40
41
  - app/channels/turbo/streams/stream_name.rb
41
42
  - app/channels/turbo/streams_channel.rb