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 +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/turbo.min.js +24 -0
- data/app/channels/turbo/streams/stream_name.rb +7 -0
- data/app/channels/turbo/streams_channel.rb +30 -2
- data/app/controllers/turbo/frames/frame_request.rb +5 -1
- data/app/helpers/turbo/streams_helper.rb +7 -1
- data/app/models/concerns/turbo/broadcastable.rb +18 -1
- data/lib/install/turbo_needs_redis.rb +2 -1
- data/lib/turbo/engine.rb +9 -1
- data/lib/turbo/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 44110a857a5e33eabc67331969cd39358dfc4a47ad0ffbce7e948ba2b29ea7ca
|
|
4
|
+
data.tar.gz: 3acfe3758be58ee628a3c74ceda13bb231bafed4d7692d42410566b148218a7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
|
12
|
-
stream_from
|
|
39
|
+
if stream_name = verified_stream_name_from_params
|
|
40
|
+
stream_from stream_name
|
|
13
41
|
else
|
|
14
42
|
reject
|
|
15
43
|
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
|
-
|
|
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
|
-
|
|
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 +=
|
|
33
|
+
Rails.application.config.assets.precompile += PRECOMPILE_ASSETS
|
|
26
34
|
end
|
|
27
35
|
end
|
|
28
36
|
|
data/lib/turbo/version.rb
CHANGED
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.
|
|
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-
|
|
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
|