turbo_reflex 0.0.15 → 0.0.16
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/Gemfile.lock +5 -5
- data/README.md +2 -2
- data/app/assets/builds/turbo_reflex.js +1 -1
- data/app/assets/builds/turbo_reflex.js.map +3 -3
- data/app/javascript/events.js +1 -1
- data/app/javascript/index.js +2 -2
- data/app/javascript/state/index.js +26 -18
- data/app/javascript/state/observable.js +0 -2
- data/app/javascript/turbo.js +5 -6
- data/lib/turbo_reflex/runner.rb +4 -4
- data/lib/turbo_reflex/state.rb +5 -0
- data/lib/turbo_reflex/state_manager.rb +24 -7
- data/lib/turbo_reflex/version.rb +1 -1
- data/package.json +1 -1
- data/tags +145 -136
- data/turbo_reflex.gemspec +1 -1
- data/yarn-error.log +252 -216
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28c80e662c56938687ac7ce0f9cc14365eabed39d13ff93b6ad09e2e995f695a
|
|
4
|
+
data.tar.gz: eebeee00a0b3b4a4626d4b8fbb55eb9373746618d153369c3865b37fc0c26317
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6d58af7eea4777ff40c88e5b04449553032b28c1a35c00bea803650acbccda273d259959f23ed9150cf90d498a802f37aad9cc23222f3a23b4b55c9d8356d988
|
|
7
|
+
data.tar.gz: 2897fe8eff7eccb32fa633248f6b9d667e09c3b33d1ad404ff53debf0551516e1f1bc4f7ce58628d6bdb385fe4b41283f86013d6d5362c7543a4e0df1e57d7ab
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
turbo_reflex (0.0.
|
|
4
|
+
turbo_reflex (0.0.16)
|
|
5
5
|
rails (>= 6.1)
|
|
6
6
|
turbo-rails (>= 1.1)
|
|
7
7
|
turbo_ready (>= 0.1)
|
|
@@ -81,7 +81,7 @@ GEM
|
|
|
81
81
|
bindex (0.8.1)
|
|
82
82
|
builder (3.2.4)
|
|
83
83
|
byebug (11.1.3)
|
|
84
|
-
capybara (3.
|
|
84
|
+
capybara (3.38.0)
|
|
85
85
|
addressable
|
|
86
86
|
matrix
|
|
87
87
|
mini_mime (>= 0.1.3)
|
|
@@ -156,7 +156,7 @@ GEM
|
|
|
156
156
|
pry-rails (0.3.9)
|
|
157
157
|
pry (>= 0.10.4)
|
|
158
158
|
public_suffix (5.0.0)
|
|
159
|
-
puma (
|
|
159
|
+
puma (6.0.0)
|
|
160
160
|
nio4r (~> 2.0)
|
|
161
161
|
racc (1.6.0)
|
|
162
162
|
rack (2.2.4)
|
|
@@ -210,7 +210,7 @@ GEM
|
|
|
210
210
|
rubocop-ast (>= 0.4.0)
|
|
211
211
|
ruby-progressbar (1.11.0)
|
|
212
212
|
rubyzip (2.3.2)
|
|
213
|
-
selenium-webdriver (4.
|
|
213
|
+
selenium-webdriver (4.6.1)
|
|
214
214
|
childprocess (>= 0.5, < 5.0)
|
|
215
215
|
rexml (~> 3.2, >= 3.2.5)
|
|
216
216
|
rubyzip (>= 1.2.2, < 3.0)
|
|
@@ -280,7 +280,7 @@ DEPENDENCIES
|
|
|
280
280
|
pry-byebug
|
|
281
281
|
pry-doc
|
|
282
282
|
pry-rails
|
|
283
|
-
puma
|
|
283
|
+
puma
|
|
284
284
|
rake
|
|
285
285
|
rexml
|
|
286
286
|
rouge
|
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
</h1>
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="http://blog.codinghorror.com/the-best-code-is-no-code-at-all/">
|
|
11
|
-
<img alt="Lines of Code" src="https://img.shields.io/badge/loc-
|
|
11
|
+
<img alt="Lines of Code" src="https://img.shields.io/badge/loc-1134-47d299.svg" />
|
|
12
12
|
</a>
|
|
13
13
|
<a href="https://codeclimate.com/github/hopsoft/turbo_reflex/maintainability">
|
|
14
14
|
<img src="https://api.codeclimate.com/v1/badges/fe1162a742fe83a4fdfd/maintainability" />
|
|
@@ -161,7 +161,7 @@ This example illustrates how to use TurboReflex to manage upvotes on a Post.
|
|
|
161
161
|
<!-- app/views/posts/show.html.erb -->
|
|
162
162
|
<%= turbo_frame_tag dom_id(@post) do %>
|
|
163
163
|
<a href="#" data-turbo-reflex="PostReflex#upvote">Upvote</a>
|
|
164
|
-
Upvote Count: <%= @post.votes
|
|
164
|
+
Upvote Count: <%= @post.votes %>
|
|
165
165
|
<% end %>
|
|
166
166
|
```
|
|
167
167
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var L=class{get element(){return document.querySelector('meta[name="turbo-reflex"]')}get token(){return this.element.getAttribute("content")}get busy(){return this.element.dataset.busy==="true"}set busy(t){return this.element.dataset.busy=!!t}},s=new L;var f={start:"turbo-reflex:start",success:"turbo-reflex:success",finish:"turbo-reflex:finish",abort:"turbo-reflex:abort",clientError:"turbo-reflex:client-error",serverError:"turbo-reflex:server-error"},d={stateLoad:"turbo-reflex:state-load",stateChange:"turbo-reflex:state-change"},l={...f,...d};function a(e,t=document,r={},n=!1){try{t=t||document;let o=new CustomEvent(e,{detail:r,cancelable:!1,bubbles:!0});t.dispatchEvent(o)}catch(o){if(n)throw o;a(f.clientError,t,{error:o,...r},!0)}}var S;function g(e,t=null){if(!e||typeof e!="object")return e;let r=new Proxy(e,{deleteProperty(n,o){return delete n[o],a(d.stateChange,s.element,{state:S}),!0},set(n,o,T,pe){return n[o]=g(T,this),a(d.stateChange,s.element,{state:S}),!0}});if(Array.isArray(e))e.forEach((n,o)=>e[o]=g(n,r));else if(typeof e=="object")for(let[n,o]of Object.entries(e))e[n]=g(o,r);return t||(S=r),r}var q=g;var H,p,E,w;function O(){let e=atob(s.element.dataset.state);E={},p=q(JSON.parse(e)),H={...p},delete s.element.dataset.clientStateChange,setTimeout(()=>a(d.stateLoad,s.element,{state:p}))}function V(e){s.element.dataset.clientStateChange||e.forEach(t=>{t.attributeName==="data-state"&&O()})}function R(){w||(w=new MutationObserver(V),w.observe(s.element,{attributes:!0}))}s.element?(O(),R()):(addEventListener("DOMContentLoaded",O),addEventListener("DOMContentLoaded",R));addEventListener("turbo:load",R);addEventListener("turbo:frame-load",R);addEventListener(d.stateChange,e=>{E={};for(let[t,r]of Object.entries(p))H[t]!==r&&(E[t]=r);s.element.dataset.clientStateChange=!0,s.element.dataset.state=btoa(JSON.stringify(p))});var b={events:d,get current(){return p},get payloadChunks(){return btoa(JSON.stringify(E)).match(/.{1,2000}/g)}};function B(e){let t="<html",r="</html",n=e.indexOf(t),o=e.lastIndexOf(r);if(n>=0&&o>=0){let T=e.slice(e.indexOf(">",n)+1,o);document.documentElement.innerHTML=T}}function G(e){document.body.insertAdjacentHTML("beforeend",e)}var m={append:G,replaceDocument:B};var k={};function z(e){k[e.id]=e}function K(e){delete k[e]}var y={add:z,remove:K,get reflexes(){return[...Object.values(k)]},get length(){return Object.keys(k).length}};function X(e){e.detail.endedAt=new Date().getTime(),e.detail.milliseconds=e.detail.endedAt-e.detail.startedAt,setTimeout(()=>a(f.finish,e.target,e.detail),20)}addEventListener(f.serverError,X);addEventListener(f.success,X);addEventListener(f.finish,e=>y.remove(e.detail.id),!0);var u={events:f};var C={};addEventListener("turbo:before-fetch-request",e=>{let t=e.target.closest("turbo-frame"),{fetchOptions:r}=e.detail;if(s.busy){let n=["text/vnd.turbo-reflex.html",r.headers.Accept];n=n.filter(o=>o&&o.trim().length>0).join(", "),r.headers.Accept=n,r.headers["TurboReflex-Token"]=s.token}b.payloadChunks.forEach((n,o)=>{r.headers[`TurboReflex-State-${o.toString().padStart(4,"0")}`]=n})});addEventListener("turbo:before-fetch-response",e=>{let t=e.target.closest("turbo-frame"),{fetchResponse:r}=e.detail;if(t&&(C[t.id]=t.src),r.header("TurboReflex")){if(r.statusCode<200||r.statusCode>399){let n=`Server returned a ${r.statusCode} status code! TurboReflex requires 2XX-3XX status codes.`;a(u.events.clientError,document,{...e.detail,error:n},!0)}r.header("TurboReflex")==="Append"&&(e.preventDefault(),r.responseText.then(n=>m.append(n)))}});addEventListener("turbo:frame-load",e=>{let t=e.target.closest("turbo-frame");t.dataset.turboReflexSrc=C[t.id]||t.src||t.dataset.turboReflexSrc,delete C[t.id]});var Q={frameAttribute:"data-turbo-frame",methodAttribute:"data-turbo-method",reflexAttribute:"data-turbo-reflex"},i={...Q};var A={},I;function W(e,t){A[e]=t,document.addEventListener(e,I,!0)}function Y(e){return Object.keys(A).find(t=>!!A[t].find(r=>Array.from(document.querySelectorAll(r)).find(n=>n===e)))}function Z(e,t){return e===Y(t)}var c={events:A,register:W,isRegisteredForElement:Z,set handler(e){I=e}};function ee(e){return e.closest(`[${i.reflexAttribute}]`)}function te(e){return e.closest("turbo-frame")}function re(e,t={}){if(e.tagName.toLowerCase()!=="select")return t.value=e.value||null;if(!e.multiple)return t.value=e.options[e.selectedIndex].value;t.values=Array.from(e.options).reduce((r,n)=>(n.selected&&r.push(n.value),r),[])}function ne(e){let t=Array.from(e.attributes).reduce((r,n)=>{let o=n.value;return r[n.name]=o,r},{});return t.tag=e.tagName,t.checked=!!e.checked,t.disabled=!!e.disabled,re(e,t),delete t.class,delete t.action,delete t.href,delete t[i.reflexAttribute],delete t[i.frameAttribute],t}var h={buildAttributePayload:ne,findClosestReflex:ee,findClosestFrame:te};function oe(e,t={}){t.token=s.token;let r=document.createElement("input");r.type="hidden",r.name="turbo_reflex",r.value=JSON.stringify(t),e.appendChild(r)}var M={invokeReflex:oe};function se(e,t={}){let r=document.createElement("a");r.href=e;let n=new URL(r);return n.searchParams.set("turbo_reflex",JSON.stringify(t)),n}var x={build:se};function ae(e,t){let r=t.src;t={...t},delete t.src,e.src=x.build(r,t)}var D={invokeReflex:ae};function ie(e,t={}){let r=t.src;t={...t},delete t.src,delete t.href,e.setAttribute("href",x.build(r,t))}var P={invokeReflex:ie};function le(e){let t=e.target;a(u.events.abort,document,{xhr:t,...e.detail})}function N(e){let t=e.target;t.getResponseHeader("TurboReflex")==="Append"?m.append(t.responseText):m.replaceDocument(t.responseText);let r=`Server returned a ${t.status} status code! TurboReflex requires 2XX-3XX status codes.`;a(u.events.clientError,document,{xhr:t,...e.detail,error:r},!0)}function ue(e){let t=e.target;if(t.status<200||t.status>399)return N(e);let r=t.responseText;t.getResponseHeader("TurboReflex")==="Append"?m.append(t.responseText):m.replaceDocument(t.responseText)}function fe(e){let t=e.src;e={...e},delete e.src;try{let r=new XMLHttpRequest;r.open("GET",x.build(t,e),!0),r.setRequestHeader("Accept","text/vnd.turbo-reflex.html, text/html, application/xhtml+xml"),r.setRequestHeader("TurboReflex-Token",s.token),b.payloadChunks.forEach((n,o)=>r.setRequestHeader(`TurboReflex-State-${o.toString().padStart(4,"0")}`,n)),r.addEventListener("abort",le),r.addEventListener("error",N),r.addEventListener("load",ue),r.send()}catch(r){let n=`Unexpected error sending HTTP request! ${r.message}`;N(r,{detail:{message:n}})}}var _={invokeReflex:fe};function $(e,t){return t=t||{dataset:{}},e.href||t.src||t.dataset.turboReflexSrc||location.href}function de(e){let t=h.findClosestFrame(e),{turboFrame:r,turboMethod:n}=e.dataset;return e.tagName.toLowerCase()==="form"?{name:"form",reason:"Element is a form.",frame:t,src:e.action,invokeReflex:M.invokeReflex}:n&&n.length>0?{name:"method",reason:"Element defines data-turbo-method.",frame:t,src:e.href,invokeReflex:P.invokeReflex}:r&&r!=="_self"?(t=document.getElementById(r),{name:"frame",reason:"element targets a frame that is not _self",frame:t,src:$(e,t),invokeReflex:D.invokeReflex}):(!r||r==="_self")&&t?{name:"frame",reason:"element does NOT target a frame or targets _self and is contained by a frame",frame:t,src:$(e,t),invokeReflex:D.invokeReflex}:{name:"window",reason:"element matches one or more of the following conditions (targets _top, does NOT target a frame, is NOT contained by a frame)",frame:null,src:$(e),invokeReflex:_.invokeReflex}}var j={find:de};var v="unknown",F={debug:Object.values(l),info:Object.values(l),warn:[l.abort,l.clientError,l.serverError],error:[l.clientError,l.serverError],unknown:[]};Object.values(l).forEach(e=>{addEventListener(e,t=>{F[v].includes(t.type)&&console[v==="debug"?"log":v](t.type,t.detail)})});var J={get level(){return v},set level(e){return Object.keys(F).includes(e)||(e="unknown"),v=e}};function ce(){return([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,e=>(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16))}var U={v4:ce};function me(e){let t,r={};try{if(t=h.findClosestReflex(e.target),!t||!c.isRegisteredForElement(e.type,t))return;let n=j.find(t);switch(r={id:`reflex-${U.v4()}`,name:t.dataset.turboReflex,driver:n.name,src:n.src,frameId:n.frame?n.frame.id:null,elementId:t.id.length>0?t.id:null,elementAttributes:h.buildAttributePayload(t),startedAt:new Date().getTime()},y.add(r),a(u.events.start,t,r),["frame","window"].includes(n.name)&&e.preventDefault(),s.busy=!0,setTimeout(()=>s.busy=!1,10),n.name){case"method":return n.invokeReflex(t,r);case"form":return n.invokeReflex(t,r);case"frame":return n.invokeReflex(n.frame,r);case"window":return n.invokeReflex(r)}}catch(n){a(u.events.clientError,t,{error:n,...r})}}c.handler=me;c.register("change",[`input[${i.reflexAttribute}]`,`select[${i.reflexAttribute}]`,`textarea[${i.reflexAttribute}]`]);c.register("submit",[`form[${i.reflexAttribute}]`]);c.register("click",[`[${i.reflexAttribute}]`]);var yt=self.TurboReflex={logger:J,schema:i,registerEventDelegate:c.register,get eventDelegates(){return{...c.events}},get lifecycleEvents(){return[...Object.values(u.events)]},get state(){return b.current}};export{yt as default};
|
|
2
2
|
//# sourceMappingURL=turbo_reflex.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../javascript/meta.js", "../../javascript/events.js", "../../javascript/state/observable.js", "../../javascript/state/index.js", "../../javascript/renderer.js", "../../javascript/activity.js", "../../javascript/lifecycle.js", "../../javascript/turbo.js", "../../javascript/schema.js", "../../javascript/delegates.js", "../../javascript/elements.js", "../../javascript/drivers/form.js", "../../javascript/urls.js", "../../javascript/drivers/frame.js", "../../javascript/drivers/method.js", "../../javascript/drivers/window.js", "../../javascript/drivers/index.js", "../../javascript/logger.js", "../../javascript/uuids.js", "../../javascript/index.js"],
|
|
4
|
-
"sourcesContent": ["class Meta {\n get element () {\n return document.querySelector('meta[name=\"turbo-reflex\"]')\n }\n\n get token () {\n return this.element.getAttribute('content')\n }\n\n get busy () {\n return this.element.dataset.busy === 'true'\n }\n\n set busy (value) {\n return (this.element.dataset.busy = !!value)\n }\n}\n\nexport default new Meta()\n", "export const lifecycleEvents = {\n start: 'turbo-reflex:start',\n success: 'turbo-reflex:success',\n finish: 'turbo-reflex:finish',\n abort: 'turbo-reflex:abort',\n clientError: 'turbo-reflex:client-error',\n serverError: 'turbo-reflex:server-error'\n}\n\nexport const stateEvents = {\n beforeStateChange: 'turbo-reflex:before-state-change',\n stateChange: 'turbo-reflex:state-change'\n}\n\nexport const allEvents = { ...lifecycleEvents, ...stateEvents }\n\nexport function dispatch (name, target = document, detail = {}, raise = false) {\n try {\n target = target || document\n const event = new CustomEvent(name, {\n detail,\n cancelable: false,\n bubbles: true\n })\n target.dispatchEvent(event)\n } catch (error) {\n if (raise) throw error\n dispatch(lifecycleEvents.clientError, target, { error, ...detail }, true)\n }\n}\n", "import meta from '../meta'\nimport { dispatch, stateEvents as events } from '../events'\n\nlet head\n\nfunction observable (object, parent = null) {\n if (!object || typeof object !== 'object') return object\n\n const proxy = new Proxy(object, {\n deleteProperty (target, key) {\n dispatch(events.beforeStateChange, meta.element, { state: head })\n delete target[key]\n dispatch(events.stateChange, meta.element, { state: head })\n return true\n },\n\n set (target, key, value, receiver) {\n dispatch(events.beforeStateChange, meta.element, { state: head })\n target[key] = observable(value, this)\n dispatch(events.stateChange, meta.element, { state: head })\n return true\n }\n })\n\n if (Array.isArray(object)) {\n object.forEach((value, index) => (object[index] = observable(value, proxy)))\n } else if (typeof object === 'object') {\n for (const [key, value] of Object.entries(object))\n object[key] = observable(value, proxy)\n }\n\n if (!parent) head = proxy\n return proxy\n}\n\nexport default observable\n", "import meta from '../meta'\nimport observable from './observable'\nimport { stateEvents as events } from '../events'\n\nlet oldState, state, changedState\nlet observer\n\nfunction loadState () {\n const json = atob(meta.element.dataset.state)\n changedState = {}\n oldState = state = observable(JSON.parse(json))\n}\n\nfunction initObserver () {\n if (observer) observer.disconnect()\n observer = new MutationObserver(loadState)\n observer.observe(meta.element, {\n attributes: true,\n attributeFilter: ['data-state']\n })\n}\n\nif (meta.element) {\n loadState()\n initObserver()\n} else {\n addEventListener('DOMContentLoaded', loadState)\n addEventListener('DOMContentLoaded', initObserver)\n}\naddEventListener('turbo:load', initObserver)\naddEventListener('turbo:frame-load', initObserver)\n\naddEventListener(\n events.beforeStateChange,\n event => (oldState = JSON.parse(JSON.stringify(state)))\n)\n\naddEventListener(events.stateChange, event => {\n changedState = {}\n for (const [key, value] of Object.entries(state))\n if (oldState[key] !== value) changedState[key] = value\n meta.element.dataset.state = btoa(JSON.stringify(state))\n})\n\nexport { state }\nexport default {\n events,\n\n // The UI state changes are split into chunks and sent to the server in an HTTP request header.\n // Max size for an HTTP header is around 4k or 4,000 bytes.\n // A Base64 character is an 8-bit-padded ASCII character... or 1 byte\n //\n // SEE: lib/state.rb - for info on how `state` is serialized/deserialized\n get payloadChunks () {\n return btoa(JSON.stringify(changedState)).match(/.{1,2000}/g)\n }\n}\n", "function replaceDocument (content) {\n const head = '<html'\n const tail = '</html'\n const headIndex = content.indexOf(head)\n const tailIndex = content.lastIndexOf(tail)\n if (headIndex >= 0 && tailIndex >= 0) {\n const html = content.slice(content.indexOf('>', headIndex) + 1, tailIndex)\n document.documentElement.innerHTML = html\n }\n}\n\nfunction append (content) {\n document.body.insertAdjacentHTML('beforeend', content)\n}\n\nexport default { append, replaceDocument }\n", "const active = {}\n\nfunction add (payload) {\n active[payload.id] = payload\n}\n\nfunction remove (id) {\n delete active[id]\n}\n\nexport default {\n add,\n remove,\n get reflexes () {\n return [...Object.values(active)]\n },\n get length () {\n return Object.keys(active).length\n }\n}\n", "import activity from './activity'\nimport { dispatch, lifecycleEvents as events } from './events'\n\nfunction finish (event) {\n event.detail.endedAt = new Date().getTime()\n event.detail.milliseconds = event.detail.endedAt - event.detail.startedAt\n setTimeout(() => dispatch(events.finish, event.target, event.detail), 20)\n}\n\naddEventListener(events.serverError, finish)\naddEventListener(events.success, finish)\naddEventListener(events.finish, event => activity.remove(event.detail.id), true)\n\nexport default { events }\n", "import meta from './meta'\nimport state from './state'\nimport renderer from './renderer'\nimport { dispatch } from './events'\nimport lifecycle from './lifecycle'\n\nconst frameSources = {}\n\n// fires before making a turbo HTTP request\naddEventListener('turbo:before-fetch-request', event => {\n const frame = event.target.closest('turbo-frame')\n const { fetchOptions } = event.detail\n\n // reflex invoked and busy\n if (meta.busy) {\n let acceptHeaders = [\n 'text/vnd.turbo-reflex.html',\n fetchOptions.headers['Accept']\n ]\n acceptHeaders = acceptHeaders\n .filter(entry => entry && entry.trim().length > 0)\n .join(', ')\n fetchOptions.headers['Accept'] = acceptHeaders\n fetchOptions.headers['TurboReflex-Token'] = meta.token\n }\n\n // always send state\n state.payloadChunks.forEach(\n (chunk, i) =>\n (fetchOptions.headers[\n `TurboReflex-State-${i.toString().padStart(4, '0')}`\n ] = chunk)\n )\n})\n\n// fires after receiving a turbo HTTP response\naddEventListener('turbo:before-fetch-response', event => {\n const frame = event.target.closest('turbo-frame')\n const { fetchResponse: response } = event.detail\n\n if (frame) frameSources[frame.id] = frame.src\n\n if (response.header('TurboReflex')) {\n if (response.statusCode < 200 || response.statusCode > 399) {\n const error = `Server returned a ${response.statusCode} status code! TurboReflex requires 2XX-3XX status codes.`\n dispatch(\n lifecycle.events.clientError,\n document,\n { ...event.detail, error },\n true\n )\n }\n\n if (response.header('TurboReflex') === 'Append') {\n event.preventDefault()\n response.responseText.then(content => renderer.append(content))\n }\n }\n})\n\n// fires when a frame element is navigated and finishes loading\naddEventListener('turbo:frame-load', event => {\n const frame = event.target.closest('turbo-frame')\n frame.dataset.turboReflexSrc =\n frameSources[frame.id] || frame.src || frame.dataset.turboReflexSrc\n delete frameSources[frame.id]\n})\n", "const schema = {\n frameAttribute: 'data-turbo-frame',\n methodAttribute: 'data-turbo-method',\n reflexAttribute: 'data-turbo-reflex'\n}\n\nexport default { ...schema }\n", "const events = {}\nlet eventListener\n\nfunction register (eventName, selectors) {\n events[eventName] = selectors\n document.addEventListener(eventName, eventListener, true)\n}\n\nfunction getRegisteredEventNameForElement (element) {\n return Object.keys(events).find(eventName => {\n return !!events[eventName].find(selector =>\n Array.from(document.querySelectorAll(selector)).find(el => el === element)\n )\n })\n}\n\nfunction isRegisteredForElement (eventName, element) {\n return eventName === getRegisteredEventNameForElement(element)\n}\n\nexport default {\n events,\n register,\n isRegisteredForElement,\n set handler (fn) {\n eventListener = fn\n }\n}\n", "import schema from './schema'\nimport lifecycle from './lifecycle'\n\nfunction findClosestReflex (element) {\n return element.closest(`[${schema.reflexAttribute}]`)\n}\n\nfunction findClosestFrame (element) {\n return element.closest('turbo-frame')\n}\n\nfunction assignElementValueToPayload (element, payload = {}) {\n if (element.tagName.toLowerCase() !== 'select')\n return (payload.value = element.value || null)\n\n if (!element.multiple)\n return (payload.value = element.options[element.selectedIndex].value)\n\n payload.values = Array.from(element.options).reduce((memo, option) => {\n if (option.selected) memo.push(option.value)\n return memo\n }, [])\n}\n\nfunction buildAttributePayload (element) {\n const payload = Array.from(element.attributes).reduce((memo, attr) => {\n let value = attr.value\n memo[attr.name] = value\n return memo\n }, {})\n\n payload.tag = element.tagName\n payload.checked = !!element.checked\n payload.disabled = !!element.disabled\n assignElementValueToPayload(element, payload)\n\n // reduce payload size to keep URL length smaller\n delete payload.class\n delete payload.action\n delete payload.href\n delete payload[schema.reflexAttribute]\n delete payload[schema.frameAttribute]\n\n return payload\n}\n\nexport default {\n buildAttributePayload,\n findClosestReflex,\n findClosestFrame\n}\n", "import meta from '../meta'\n\nfunction invokeReflex (form, payload = {}) {\n payload.token = meta.token\n const input = document.createElement('input')\n input.type = 'hidden'\n input.name = 'turbo_reflex'\n input.value = JSON.stringify(payload)\n form.appendChild(input)\n}\n\nexport default { invokeReflex }\n", "function build (urlString, payload = {}) {\n const a = document.createElement('a')\n a.href = urlString\n const url = new URL(a)\n url.searchParams.set('turbo_reflex', JSON.stringify(payload))\n return url\n}\n\nexport default { build }\n", "import urls from '../urls'\n\nfunction invokeReflex (frame, payload) {\n const src = payload.src\n payload = { ...payload }\n delete payload.src\n frame.src = urls.build(src, payload)\n}\n\nexport default { invokeReflex }\n", "import urls from '../urls'\n\nfunction invokeReflex (element, payload = {}) {\n const src = payload.src\n payload = { ...payload }\n delete payload.src\n delete payload.href\n element.setAttribute('href', urls.build(src, payload))\n}\n\nexport default { invokeReflex }\n", "import meta from '../meta'\nimport state from '../state'\nimport { dispatch } from '../events'\nimport lifecycle from '../lifecycle'\nimport urls from '../urls'\nimport renderer from '../renderer'\n\nfunction aborted (event) {\n const xhr = event.target\n dispatch(lifecycle.events.abort, document, { xhr, ...event.detail })\n}\n\nfunction errored (event) {\n const xhr = event.target\n\n xhr.getResponseHeader('TurboReflex') === 'Append'\n ? renderer.append(xhr.responseText)\n : renderer.replaceDocument(xhr.responseText)\n\n const error = `Server returned a ${xhr.status} status code! TurboReflex requires 2XX-3XX status codes.`\n\n dispatch(\n lifecycle.events.clientError,\n document,\n { xhr, ...event.detail, error },\n true\n )\n}\n\nfunction loaded (event) {\n const xhr = event.target\n if (xhr.status < 200 || xhr.status > 399) return errored(event)\n const content = xhr.responseText\n xhr.getResponseHeader('TurboReflex') === 'Append'\n ? renderer.append(xhr.responseText)\n : renderer.replaceDocument(xhr.responseText)\n}\n\nfunction invokeReflex (payload) {\n const src = payload.src\n payload = { ...payload }\n delete payload.src\n\n try {\n const xhr = new XMLHttpRequest()\n xhr.open('GET', urls.build(src, payload), true)\n xhr.setRequestHeader(\n 'Accept',\n 'text/vnd.turbo-reflex.html, text/html, application/xhtml+xml'\n )\n xhr.setRequestHeader('TurboReflex-Token', meta.token)\n state.payloadChunks.forEach((chunk, i) =>\n xhr.setRequestHeader(\n `TurboReflex-State-${i.toString().padStart(4, '0')}`,\n chunk\n )\n )\n\n xhr.addEventListener('abort', aborted)\n xhr.addEventListener('error', errored)\n xhr.addEventListener('load', loaded)\n xhr.send()\n } catch (ex) {\n const message = `Unexpected error sending HTTP request! ${ex.message}`\n errored(ex, { detail: { message } })\n }\n}\n\nexport default { invokeReflex }\n", "import elements from '../elements'\nimport formDriver from './form'\nimport frameDriver from './frame'\nimport methodDriver from './method'\nimport windowDriver from './window'\n\nfunction src (element, frame) {\n frame = frame || { dataset: {} }\n return (\n element.href || frame.src || frame.dataset.turboReflexSrc || location.href\n )\n}\n\nfunction find (element) {\n let frame = elements.findClosestFrame(element)\n const { turboFrame, turboMethod } = element.dataset\n\n if (element.tagName.toLowerCase() === 'form')\n return {\n name: 'form',\n reason: 'Element is a form.',\n frame,\n src: element.action,\n invokeReflex: formDriver.invokeReflex\n }\n\n if (turboMethod && turboMethod.length > 0)\n return {\n name: 'method',\n reason: 'Element defines data-turbo-method.',\n frame,\n src: element.href,\n invokeReflex: methodDriver.invokeReflex\n }\n\n // element targets a frame that is not _self\n if (turboFrame && turboFrame !== '_self') {\n frame = document.getElementById(turboFrame)\n return {\n name: 'frame',\n reason: 'element targets a frame that is not _self',\n frame,\n src: src(element, frame),\n invokeReflex: frameDriver.invokeReflex\n }\n }\n\n // element does NOT target a frame or targets _self and is contained by a frame\n if ((!turboFrame || turboFrame === '_self') && frame)\n return {\n name: 'frame',\n reason:\n 'element does NOT target a frame or targets _self and is contained by a frame',\n frame,\n src: src(element, frame),\n invokeReflex: frameDriver.invokeReflex\n }\n\n // element matches one or more of the following conditions\n // - targets _top\n // - does NOT target a frame\n // - is NOT contained by a frame\n return {\n name: 'window',\n reason:\n 'element matches one or more of the following conditions (targets _top, does NOT target a frame, is NOT contained by a frame)',\n frame: null,\n src: src(element),\n invokeReflex: windowDriver.invokeReflex\n }\n}\n\nexport default { find }\n", "import { allEvents as events } from './events'\n\nlet currentLevel = 'unknown'\n\nconst logLevels = {\n debug: Object.values(events),\n info: Object.values(events),\n warn: [events.abort, events.clientError, events.serverError],\n error: [events.clientError, events.serverError],\n unknown: []\n}\n\nObject.values(events).forEach(name => {\n addEventListener(name, event => {\n if (logLevels[currentLevel].includes(event.type)) {\n const level = currentLevel === 'debug' ? 'log' : currentLevel\n console[level](event.type, event.detail)\n }\n })\n})\n\nexport default {\n get level () {\n return currentLevel\n },\n set level (value) {\n if (!Object.keys(logLevels).includes(value)) value = 'unknown'\n return (currentLevel = value)\n }\n}\n", "function v4 () {\n return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>\n (\n c ^\n (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))\n ).toString(16)\n )\n}\n\nexport default { v4 }\n", "import './turbo'\nimport schema from './schema'\nimport { dispatch } from './events'\nimport activity from './activity'\nimport delegates from './delegates'\nimport drivers from './drivers'\nimport meta from './meta'\nimport elements from './elements'\nimport lifecycle from './lifecycle'\nimport logger from './logger'\nimport { state } from './state'\nimport urls from './urls'\nimport uuids from './uuids'\n\nfunction invokeReflex (event) {\n let element\n let payload = {}\n\n try {\n element = elements.findClosestReflex(event.target)\n if (!element) return\n if (!delegates.isRegisteredForElement(event.type, element)) return\n\n const driver = drivers.find(element)\n\n // payload sent to server (also used for lifecycle event.detail)\n payload = {\n id: `reflex-${uuids.v4()}`,\n name: element.dataset.turboReflex,\n driver: driver.name,\n src: driver.src,\n frameId: driver.frame ? driver.frame.id : null,\n elementId: element.id.length > 0 ? element.id : null,\n elementAttributes: elements.buildAttributePayload(element),\n startedAt: new Date().getTime()\n }\n\n activity.add(payload)\n dispatch(lifecycle.events.start, element, payload)\n\n if (['frame', 'window'].includes(driver.name)) event.preventDefault()\n\n meta.busy = true\n setTimeout(() => (meta.busy = false), 10)\n\n switch (driver.name) {\n case 'method':\n return driver.invokeReflex(element, payload)\n case 'form':\n return driver.invokeReflex(element, payload)\n case 'frame':\n return driver.invokeReflex(driver.frame, payload)\n case 'window':\n return driver.invokeReflex(payload)\n }\n } catch (error) {\n dispatch(lifecycle.events.clientError, element, {\n error,\n ...payload\n })\n }\n}\n\n// wire things up and setup defaults for event delegation\ndelegates.handler = invokeReflex\ndelegates.register('change', [\n `input[${schema.reflexAttribute}]`,\n `select[${schema.reflexAttribute}]`,\n `textarea[${schema.reflexAttribute}]`\n])\n// delegates.register('mousedown', [\n// `[${schema.reflexAttribute}][${schema.methodAttribute}]`\n// ])\ndelegates.register('submit', [`form[${schema.reflexAttribute}]`])\ndelegates.register('click', [`[${schema.reflexAttribute}]`])\n\nexport default self.TurboReflex = {\n logger,\n schema,\n registerEventDelegate: delegates.register,\n get eventDelegates () {\n return { ...delegates.events }\n },\n get lifecycleEvents () {\n return [...Object.values(lifecycle.events)]\n },\n get state () {\n return state\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Meta", "value", "meta_default", "lifecycleEvents", "stateEvents", "allEvents", "dispatch", "name", "target", "detail", "raise", "event", "error", "head", "observable", "object", "parent", "proxy", "target", "key", "dispatch", "stateEvents", "meta_default", "value", "receiver", "index", "observable_default", "
|
|
4
|
+
"sourcesContent": ["class Meta {\n get element () {\n return document.querySelector('meta[name=\"turbo-reflex\"]')\n }\n\n get token () {\n return this.element.getAttribute('content')\n }\n\n get busy () {\n return this.element.dataset.busy === 'true'\n }\n\n set busy (value) {\n return (this.element.dataset.busy = !!value)\n }\n}\n\nexport default new Meta()\n", "export const lifecycleEvents = {\n start: 'turbo-reflex:start',\n success: 'turbo-reflex:success',\n finish: 'turbo-reflex:finish',\n abort: 'turbo-reflex:abort',\n clientError: 'turbo-reflex:client-error',\n serverError: 'turbo-reflex:server-error'\n}\n\nexport const stateEvents = {\n stateLoad: 'turbo-reflex:state-load',\n stateChange: 'turbo-reflex:state-change'\n}\n\nexport const allEvents = { ...lifecycleEvents, ...stateEvents }\n\nexport function dispatch (name, target = document, detail = {}, raise = false) {\n try {\n target = target || document\n const event = new CustomEvent(name, {\n detail,\n cancelable: false,\n bubbles: true\n })\n target.dispatchEvent(event)\n } catch (error) {\n if (raise) throw error\n dispatch(lifecycleEvents.clientError, target, { error, ...detail }, true)\n }\n}\n", "import meta from '../meta'\nimport { dispatch, stateEvents as events } from '../events'\n\nlet head\n\nfunction observable (object, parent = null) {\n if (!object || typeof object !== 'object') return object\n\n const proxy = new Proxy(object, {\n deleteProperty (target, key) {\n delete target[key]\n dispatch(events.stateChange, meta.element, { state: head })\n return true\n },\n\n set (target, key, value, receiver) {\n target[key] = observable(value, this)\n dispatch(events.stateChange, meta.element, { state: head })\n return true\n }\n })\n\n if (Array.isArray(object)) {\n object.forEach((value, index) => (object[index] = observable(value, proxy)))\n } else if (typeof object === 'object') {\n for (const [key, value] of Object.entries(object))\n object[key] = observable(value, proxy)\n }\n\n if (!parent) head = proxy\n return proxy\n}\n\nexport default observable\n", "import meta from '../meta'\nimport observable from './observable'\nimport { dispatch, stateEvents as events } from '../events'\n\nlet loadedState, currentState, changedState\nlet observer\n\nfunction loadState () {\n const json = atob(meta.element.dataset.state)\n changedState = {}\n currentState = observable(JSON.parse(json))\n loadedState = { ...currentState }\n delete meta.element.dataset.clientStateChange\n setTimeout(() =>\n dispatch(events.stateLoad, meta.element, { state: currentState })\n )\n}\n\nfunction metaMutated (mutations) {\n if (meta.element.dataset.clientStateChange) return\n mutations.forEach(m => {\n if (m.attributeName === 'data-state') loadState()\n })\n}\n\nfunction initObserver () {\n if (observer) return\n observer = new MutationObserver(metaMutated)\n observer.observe(meta.element, { attributes: true })\n}\n\nif (meta.element) {\n loadState()\n initObserver()\n} else {\n addEventListener('DOMContentLoaded', loadState)\n addEventListener('DOMContentLoaded', initObserver)\n}\naddEventListener('turbo:load', initObserver)\naddEventListener('turbo:frame-load', initObserver)\n\naddEventListener(events.stateChange, event => {\n changedState = {}\n for (const [key, value] of Object.entries(currentState))\n if (loadedState[key] !== value) changedState[key] = value\n meta.element.dataset.clientStateChange = true\n meta.element.dataset.state = btoa(JSON.stringify(currentState))\n})\n\nexport default {\n events,\n\n get current () {\n return currentState\n },\n\n // The UI state changes are split into chunks and sent to the server in an HTTP request header.\n // Max size for an HTTP header is around 4k or 4,000 bytes.\n // A Base64 character is an 8-bit-padded ASCII character... or 1 byte\n //\n // SEE: lib/state.rb - for info on how `state` is serialized/deserialized\n get payloadChunks () {\n return btoa(JSON.stringify(changedState)).match(/.{1,2000}/g)\n }\n}\n", "function replaceDocument (content) {\n const head = '<html'\n const tail = '</html'\n const headIndex = content.indexOf(head)\n const tailIndex = content.lastIndexOf(tail)\n if (headIndex >= 0 && tailIndex >= 0) {\n const html = content.slice(content.indexOf('>', headIndex) + 1, tailIndex)\n document.documentElement.innerHTML = html\n }\n}\n\nfunction append (content) {\n document.body.insertAdjacentHTML('beforeend', content)\n}\n\nexport default { append, replaceDocument }\n", "const active = {}\n\nfunction add (payload) {\n active[payload.id] = payload\n}\n\nfunction remove (id) {\n delete active[id]\n}\n\nexport default {\n add,\n remove,\n get reflexes () {\n return [...Object.values(active)]\n },\n get length () {\n return Object.keys(active).length\n }\n}\n", "import activity from './activity'\nimport { dispatch, lifecycleEvents as events } from './events'\n\nfunction finish (event) {\n event.detail.endedAt = new Date().getTime()\n event.detail.milliseconds = event.detail.endedAt - event.detail.startedAt\n setTimeout(() => dispatch(events.finish, event.target, event.detail), 20)\n}\n\naddEventListener(events.serverError, finish)\naddEventListener(events.success, finish)\naddEventListener(events.finish, event => activity.remove(event.detail.id), true)\n\nexport default { events }\n", "import meta from './meta'\nimport state from './state'\nimport renderer from './renderer'\nimport { dispatch } from './events'\nimport lifecycle from './lifecycle'\n\nconst frameSources = {}\n\n// fires before making a turbo HTTP request\naddEventListener('turbo:before-fetch-request', event => {\n const frame = event.target.closest('turbo-frame')\n const { fetchOptions } = event.detail\n\n // reflex invoked and busy\n if (meta.busy) {\n let acceptHeaders = [\n 'text/vnd.turbo-reflex.html',\n fetchOptions.headers['Accept']\n ]\n acceptHeaders = acceptHeaders\n .filter(entry => entry && entry.trim().length > 0)\n .join(', ')\n fetchOptions.headers['Accept'] = acceptHeaders\n fetchOptions.headers['TurboReflex-Token'] = meta.token\n }\n\n // always send state\n state.payloadChunks.forEach((chunk, i) => {\n fetchOptions.headers[\n `TurboReflex-State-${i.toString().padStart(4, '0')}`\n ] = chunk\n })\n})\n\n// fires after receiving a turbo HTTP response\naddEventListener('turbo:before-fetch-response', event => {\n const frame = event.target.closest('turbo-frame')\n const { fetchResponse: response } = event.detail\n\n if (frame) frameSources[frame.id] = frame.src\n\n if (response.header('TurboReflex')) {\n if (response.statusCode < 200 || response.statusCode > 399) {\n const error = `Server returned a ${response.statusCode} status code! TurboReflex requires 2XX-3XX status codes.`\n dispatch(\n lifecycle.events.clientError,\n document,\n { ...event.detail, error },\n true\n )\n }\n\n if (response.header('TurboReflex') === 'Append') {\n event.preventDefault()\n response.responseText.then(content => renderer.append(content))\n }\n }\n})\n\n// fires when a frame element is navigated and finishes loading\naddEventListener('turbo:frame-load', event => {\n const frame = event.target.closest('turbo-frame')\n frame.dataset.turboReflexSrc =\n frameSources[frame.id] || frame.src || frame.dataset.turboReflexSrc\n delete frameSources[frame.id]\n})\n", "const schema = {\n frameAttribute: 'data-turbo-frame',\n methodAttribute: 'data-turbo-method',\n reflexAttribute: 'data-turbo-reflex'\n}\n\nexport default { ...schema }\n", "const events = {}\nlet eventListener\n\nfunction register (eventName, selectors) {\n events[eventName] = selectors\n document.addEventListener(eventName, eventListener, true)\n}\n\nfunction getRegisteredEventNameForElement (element) {\n return Object.keys(events).find(eventName => {\n return !!events[eventName].find(selector =>\n Array.from(document.querySelectorAll(selector)).find(el => el === element)\n )\n })\n}\n\nfunction isRegisteredForElement (eventName, element) {\n return eventName === getRegisteredEventNameForElement(element)\n}\n\nexport default {\n events,\n register,\n isRegisteredForElement,\n set handler (fn) {\n eventListener = fn\n }\n}\n", "import schema from './schema'\nimport lifecycle from './lifecycle'\n\nfunction findClosestReflex (element) {\n return element.closest(`[${schema.reflexAttribute}]`)\n}\n\nfunction findClosestFrame (element) {\n return element.closest('turbo-frame')\n}\n\nfunction assignElementValueToPayload (element, payload = {}) {\n if (element.tagName.toLowerCase() !== 'select')\n return (payload.value = element.value || null)\n\n if (!element.multiple)\n return (payload.value = element.options[element.selectedIndex].value)\n\n payload.values = Array.from(element.options).reduce((memo, option) => {\n if (option.selected) memo.push(option.value)\n return memo\n }, [])\n}\n\nfunction buildAttributePayload (element) {\n const payload = Array.from(element.attributes).reduce((memo, attr) => {\n let value = attr.value\n memo[attr.name] = value\n return memo\n }, {})\n\n payload.tag = element.tagName\n payload.checked = !!element.checked\n payload.disabled = !!element.disabled\n assignElementValueToPayload(element, payload)\n\n // reduce payload size to keep URL length smaller\n delete payload.class\n delete payload.action\n delete payload.href\n delete payload[schema.reflexAttribute]\n delete payload[schema.frameAttribute]\n\n return payload\n}\n\nexport default {\n buildAttributePayload,\n findClosestReflex,\n findClosestFrame\n}\n", "import meta from '../meta'\n\nfunction invokeReflex (form, payload = {}) {\n payload.token = meta.token\n const input = document.createElement('input')\n input.type = 'hidden'\n input.name = 'turbo_reflex'\n input.value = JSON.stringify(payload)\n form.appendChild(input)\n}\n\nexport default { invokeReflex }\n", "function build (urlString, payload = {}) {\n const a = document.createElement('a')\n a.href = urlString\n const url = new URL(a)\n url.searchParams.set('turbo_reflex', JSON.stringify(payload))\n return url\n}\n\nexport default { build }\n", "import urls from '../urls'\n\nfunction invokeReflex (frame, payload) {\n const src = payload.src\n payload = { ...payload }\n delete payload.src\n frame.src = urls.build(src, payload)\n}\n\nexport default { invokeReflex }\n", "import urls from '../urls'\n\nfunction invokeReflex (element, payload = {}) {\n const src = payload.src\n payload = { ...payload }\n delete payload.src\n delete payload.href\n element.setAttribute('href', urls.build(src, payload))\n}\n\nexport default { invokeReflex }\n", "import meta from '../meta'\nimport state from '../state'\nimport { dispatch } from '../events'\nimport lifecycle from '../lifecycle'\nimport urls from '../urls'\nimport renderer from '../renderer'\n\nfunction aborted (event) {\n const xhr = event.target\n dispatch(lifecycle.events.abort, document, { xhr, ...event.detail })\n}\n\nfunction errored (event) {\n const xhr = event.target\n\n xhr.getResponseHeader('TurboReflex') === 'Append'\n ? renderer.append(xhr.responseText)\n : renderer.replaceDocument(xhr.responseText)\n\n const error = `Server returned a ${xhr.status} status code! TurboReflex requires 2XX-3XX status codes.`\n\n dispatch(\n lifecycle.events.clientError,\n document,\n { xhr, ...event.detail, error },\n true\n )\n}\n\nfunction loaded (event) {\n const xhr = event.target\n if (xhr.status < 200 || xhr.status > 399) return errored(event)\n const content = xhr.responseText\n xhr.getResponseHeader('TurboReflex') === 'Append'\n ? renderer.append(xhr.responseText)\n : renderer.replaceDocument(xhr.responseText)\n}\n\nfunction invokeReflex (payload) {\n const src = payload.src\n payload = { ...payload }\n delete payload.src\n\n try {\n const xhr = new XMLHttpRequest()\n xhr.open('GET', urls.build(src, payload), true)\n xhr.setRequestHeader(\n 'Accept',\n 'text/vnd.turbo-reflex.html, text/html, application/xhtml+xml'\n )\n xhr.setRequestHeader('TurboReflex-Token', meta.token)\n state.payloadChunks.forEach((chunk, i) =>\n xhr.setRequestHeader(\n `TurboReflex-State-${i.toString().padStart(4, '0')}`,\n chunk\n )\n )\n\n xhr.addEventListener('abort', aborted)\n xhr.addEventListener('error', errored)\n xhr.addEventListener('load', loaded)\n xhr.send()\n } catch (ex) {\n const message = `Unexpected error sending HTTP request! ${ex.message}`\n errored(ex, { detail: { message } })\n }\n}\n\nexport default { invokeReflex }\n", "import elements from '../elements'\nimport formDriver from './form'\nimport frameDriver from './frame'\nimport methodDriver from './method'\nimport windowDriver from './window'\n\nfunction src (element, frame) {\n frame = frame || { dataset: {} }\n return (\n element.href || frame.src || frame.dataset.turboReflexSrc || location.href\n )\n}\n\nfunction find (element) {\n let frame = elements.findClosestFrame(element)\n const { turboFrame, turboMethod } = element.dataset\n\n if (element.tagName.toLowerCase() === 'form')\n return {\n name: 'form',\n reason: 'Element is a form.',\n frame,\n src: element.action,\n invokeReflex: formDriver.invokeReflex\n }\n\n if (turboMethod && turboMethod.length > 0)\n return {\n name: 'method',\n reason: 'Element defines data-turbo-method.',\n frame,\n src: element.href,\n invokeReflex: methodDriver.invokeReflex\n }\n\n // element targets a frame that is not _self\n if (turboFrame && turboFrame !== '_self') {\n frame = document.getElementById(turboFrame)\n return {\n name: 'frame',\n reason: 'element targets a frame that is not _self',\n frame,\n src: src(element, frame),\n invokeReflex: frameDriver.invokeReflex\n }\n }\n\n // element does NOT target a frame or targets _self and is contained by a frame\n if ((!turboFrame || turboFrame === '_self') && frame)\n return {\n name: 'frame',\n reason:\n 'element does NOT target a frame or targets _self and is contained by a frame',\n frame,\n src: src(element, frame),\n invokeReflex: frameDriver.invokeReflex\n }\n\n // element matches one or more of the following conditions\n // - targets _top\n // - does NOT target a frame\n // - is NOT contained by a frame\n return {\n name: 'window',\n reason:\n 'element matches one or more of the following conditions (targets _top, does NOT target a frame, is NOT contained by a frame)',\n frame: null,\n src: src(element),\n invokeReflex: windowDriver.invokeReflex\n }\n}\n\nexport default { find }\n", "import { allEvents as events } from './events'\n\nlet currentLevel = 'unknown'\n\nconst logLevels = {\n debug: Object.values(events),\n info: Object.values(events),\n warn: [events.abort, events.clientError, events.serverError],\n error: [events.clientError, events.serverError],\n unknown: []\n}\n\nObject.values(events).forEach(name => {\n addEventListener(name, event => {\n if (logLevels[currentLevel].includes(event.type)) {\n const level = currentLevel === 'debug' ? 'log' : currentLevel\n console[level](event.type, event.detail)\n }\n })\n})\n\nexport default {\n get level () {\n return currentLevel\n },\n set level (value) {\n if (!Object.keys(logLevels).includes(value)) value = 'unknown'\n return (currentLevel = value)\n }\n}\n", "function v4 () {\n return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>\n (\n c ^\n (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))\n ).toString(16)\n )\n}\n\nexport default { v4 }\n", "import './turbo'\nimport schema from './schema'\nimport { dispatch } from './events'\nimport activity from './activity'\nimport delegates from './delegates'\nimport drivers from './drivers'\nimport meta from './meta'\nimport elements from './elements'\nimport lifecycle from './lifecycle'\nimport logger from './logger'\nimport state from './state'\nimport urls from './urls'\nimport uuids from './uuids'\n\nfunction invokeReflex (event) {\n let element\n let payload = {}\n\n try {\n element = elements.findClosestReflex(event.target)\n if (!element) return\n if (!delegates.isRegisteredForElement(event.type, element)) return\n\n const driver = drivers.find(element)\n\n // payload sent to server (also used for lifecycle event.detail)\n payload = {\n id: `reflex-${uuids.v4()}`,\n name: element.dataset.turboReflex,\n driver: driver.name,\n src: driver.src,\n frameId: driver.frame ? driver.frame.id : null,\n elementId: element.id.length > 0 ? element.id : null,\n elementAttributes: elements.buildAttributePayload(element),\n startedAt: new Date().getTime()\n }\n\n activity.add(payload)\n dispatch(lifecycle.events.start, element, payload)\n\n if (['frame', 'window'].includes(driver.name)) event.preventDefault()\n\n meta.busy = true\n setTimeout(() => (meta.busy = false), 10)\n\n switch (driver.name) {\n case 'method':\n return driver.invokeReflex(element, payload)\n case 'form':\n return driver.invokeReflex(element, payload)\n case 'frame':\n return driver.invokeReflex(driver.frame, payload)\n case 'window':\n return driver.invokeReflex(payload)\n }\n } catch (error) {\n dispatch(lifecycle.events.clientError, element, {\n error,\n ...payload\n })\n }\n}\n\n// wire things up and setup defaults for event delegation\ndelegates.handler = invokeReflex\ndelegates.register('change', [\n `input[${schema.reflexAttribute}]`,\n `select[${schema.reflexAttribute}]`,\n `textarea[${schema.reflexAttribute}]`\n])\n// delegates.register('mousedown', [\n// `[${schema.reflexAttribute}][${schema.methodAttribute}]`\n// ])\ndelegates.register('submit', [`form[${schema.reflexAttribute}]`])\ndelegates.register('click', [`[${schema.reflexAttribute}]`])\n\nexport default self.TurboReflex = {\n logger,\n schema,\n registerEventDelegate: delegates.register,\n get eventDelegates () {\n return { ...delegates.events }\n },\n get lifecycleEvents () {\n return [...Object.values(lifecycle.events)]\n },\n get state () {\n return state.current\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Meta", "value", "meta_default", "lifecycleEvents", "stateEvents", "allEvents", "dispatch", "name", "target", "detail", "raise", "event", "error", "head", "observable", "object", "parent", "proxy", "target", "key", "dispatch", "stateEvents", "meta_default", "value", "receiver", "index", "observable_default", "loadedState", "currentState", "changedState", "observer", "loadState", "json", "meta_default", "observable_default", "dispatch", "stateEvents", "metaMutated", "mutations", "m", "initObserver", "event", "key", "value", "state_default", "replaceDocument", "content", "head", "tail", "headIndex", "tailIndex", "html", "append", "renderer_default", "active", "add", "payload", "remove", "id", "activity_default", "finish", "event", "dispatch", "lifecycleEvents", "activity_default", "lifecycle_default", "frameSources", "event", "frame", "fetchOptions", "meta_default", "acceptHeaders", "entry", "state_default", "chunk", "i", "response", "error", "dispatch", "lifecycle_default", "content", "renderer_default", "schema", "schema_default", "events", "eventListener", "register", "eventName", "selectors", "getRegisteredEventNameForElement", "element", "selector", "el", "isRegisteredForElement", "delegates_default", "fn", "findClosestReflex", "element", "schema_default", "findClosestFrame", "assignElementValueToPayload", "payload", "memo", "option", "buildAttributePayload", "attr", "value", "elements_default", "invokeReflex", "form", "payload", "meta_default", "input", "form_default", "build", "urlString", "payload", "a", "url", "urls_default", "invokeReflex", "frame", "payload", "src", "urls_default", "frame_default", "invokeReflex", "element", "payload", "src", "urls_default", "method_default", "aborted", "event", "xhr", "dispatch", "lifecycle_default", "errored", "renderer_default", "error", "loaded", "content", "invokeReflex", "payload", "src", "urls_default", "meta_default", "state_default", "chunk", "i", "ex", "message", "window_default", "src", "element", "frame", "find", "elements_default", "turboFrame", "turboMethod", "form_default", "method_default", "frame_default", "window_default", "drivers_default", "currentLevel", "logLevels", "allEvents", "name", "event", "logger_default", "value", "v4", "c", "uuids_default", "invokeReflex", "event", "element", "payload", "elements_default", "delegates_default", "driver", "drivers_default", "uuids_default", "activity_default", "dispatch", "lifecycle_default", "meta_default", "error", "schema_default", "javascript_default", "logger_default", "state_default"]
|
|
7
7
|
}
|
data/app/javascript/events.js
CHANGED
data/app/javascript/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import meta from './meta'
|
|
|
8
8
|
import elements from './elements'
|
|
9
9
|
import lifecycle from './lifecycle'
|
|
10
10
|
import logger from './logger'
|
|
11
|
-
import
|
|
11
|
+
import state from './state'
|
|
12
12
|
import urls from './urls'
|
|
13
13
|
import uuids from './uuids'
|
|
14
14
|
|
|
@@ -85,6 +85,6 @@ export default self.TurboReflex = {
|
|
|
85
85
|
return [...Object.values(lifecycle.events)]
|
|
86
86
|
},
|
|
87
87
|
get state () {
|
|
88
|
-
return state
|
|
88
|
+
return state.current
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import meta from '../meta'
|
|
2
2
|
import observable from './observable'
|
|
3
|
-
import { stateEvents as events } from '../events'
|
|
3
|
+
import { dispatch, stateEvents as events } from '../events'
|
|
4
4
|
|
|
5
|
-
let
|
|
5
|
+
let loadedState, currentState, changedState
|
|
6
6
|
let observer
|
|
7
7
|
|
|
8
8
|
function loadState () {
|
|
9
9
|
const json = atob(meta.element.dataset.state)
|
|
10
10
|
changedState = {}
|
|
11
|
-
|
|
11
|
+
currentState = observable(JSON.parse(json))
|
|
12
|
+
loadedState = { ...currentState }
|
|
13
|
+
delete meta.element.dataset.clientStateChange
|
|
14
|
+
setTimeout(() =>
|
|
15
|
+
dispatch(events.stateLoad, meta.element, { state: currentState })
|
|
16
|
+
)
|
|
12
17
|
}
|
|
13
18
|
|
|
14
|
-
function
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
attributes: true,
|
|
19
|
-
attributeFilter: ['data-state']
|
|
19
|
+
function metaMutated (mutations) {
|
|
20
|
+
if (meta.element.dataset.clientStateChange) return
|
|
21
|
+
mutations.forEach(m => {
|
|
22
|
+
if (m.attributeName === 'data-state') loadState()
|
|
20
23
|
})
|
|
21
24
|
}
|
|
22
25
|
|
|
26
|
+
function initObserver () {
|
|
27
|
+
if (observer) return
|
|
28
|
+
observer = new MutationObserver(metaMutated)
|
|
29
|
+
observer.observe(meta.element, { attributes: true })
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
if (meta.element) {
|
|
24
33
|
loadState()
|
|
25
34
|
initObserver()
|
|
@@ -30,22 +39,21 @@ if (meta.element) {
|
|
|
30
39
|
addEventListener('turbo:load', initObserver)
|
|
31
40
|
addEventListener('turbo:frame-load', initObserver)
|
|
32
41
|
|
|
33
|
-
addEventListener(
|
|
34
|
-
events.beforeStateChange,
|
|
35
|
-
event => (oldState = JSON.parse(JSON.stringify(state)))
|
|
36
|
-
)
|
|
37
|
-
|
|
38
42
|
addEventListener(events.stateChange, event => {
|
|
39
43
|
changedState = {}
|
|
40
|
-
for (const [key, value] of Object.entries(
|
|
41
|
-
if (
|
|
42
|
-
meta.element.dataset.
|
|
44
|
+
for (const [key, value] of Object.entries(currentState))
|
|
45
|
+
if (loadedState[key] !== value) changedState[key] = value
|
|
46
|
+
meta.element.dataset.clientStateChange = true
|
|
47
|
+
meta.element.dataset.state = btoa(JSON.stringify(currentState))
|
|
43
48
|
})
|
|
44
49
|
|
|
45
|
-
export { state }
|
|
46
50
|
export default {
|
|
47
51
|
events,
|
|
48
52
|
|
|
53
|
+
get current () {
|
|
54
|
+
return currentState
|
|
55
|
+
},
|
|
56
|
+
|
|
49
57
|
// The UI state changes are split into chunks and sent to the server in an HTTP request header.
|
|
50
58
|
// Max size for an HTTP header is around 4k or 4,000 bytes.
|
|
51
59
|
// A Base64 character is an 8-bit-padded ASCII character... or 1 byte
|
|
@@ -8,14 +8,12 @@ function observable (object, parent = null) {
|
|
|
8
8
|
|
|
9
9
|
const proxy = new Proxy(object, {
|
|
10
10
|
deleteProperty (target, key) {
|
|
11
|
-
dispatch(events.beforeStateChange, meta.element, { state: head })
|
|
12
11
|
delete target[key]
|
|
13
12
|
dispatch(events.stateChange, meta.element, { state: head })
|
|
14
13
|
return true
|
|
15
14
|
},
|
|
16
15
|
|
|
17
16
|
set (target, key, value, receiver) {
|
|
18
|
-
dispatch(events.beforeStateChange, meta.element, { state: head })
|
|
19
17
|
target[key] = observable(value, this)
|
|
20
18
|
dispatch(events.stateChange, meta.element, { state: head })
|
|
21
19
|
return true
|
data/app/javascript/turbo.js
CHANGED
|
@@ -25,12 +25,11 @@ addEventListener('turbo:before-fetch-request', event => {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// always send state
|
|
28
|
-
state.payloadChunks.forEach(
|
|
29
|
-
|
|
30
|
-
(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
28
|
+
state.payloadChunks.forEach((chunk, i) => {
|
|
29
|
+
fetchOptions.headers[
|
|
30
|
+
`TurboReflex-State-${i.toString().padStart(4, '0')}`
|
|
31
|
+
] = chunk
|
|
32
|
+
})
|
|
34
33
|
})
|
|
35
34
|
|
|
36
35
|
// fires after receiving a turbo HTTP response
|
data/lib/turbo_reflex/runner.rb
CHANGED
|
@@ -138,8 +138,8 @@ class TurboReflex::Runner
|
|
|
138
138
|
append_success_to_response
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
append_meta_tag_to_response_body # called before `
|
|
142
|
-
state_manager.
|
|
141
|
+
append_meta_tag_to_response_body # called before `write_cookie` so all state is emitted to the DOM
|
|
142
|
+
state_manager.write_cookie # truncates state to stay within cookie size limits (4k)
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
def update_response
|
|
@@ -147,8 +147,8 @@ class TurboReflex::Runner
|
|
|
147
147
|
return if @update_response_performed
|
|
148
148
|
@update_response_performed = true
|
|
149
149
|
|
|
150
|
-
append_meta_tag_to_response_body # called before `
|
|
151
|
-
state_manager.
|
|
150
|
+
append_meta_tag_to_response_body # called before `write_cookie` so all state is emitted to the DOM
|
|
151
|
+
state_manager.write_cookie # truncates state to stay within cookie size limits (4k)
|
|
152
152
|
append_success_to_response if reflex_succeeded?
|
|
153
153
|
end
|
|
154
154
|
|
data/lib/turbo_reflex/state.rb
CHANGED
|
@@ -44,6 +44,8 @@ class TurboReflex::StateManager
|
|
|
44
44
|
delegate :cookies, to: :runner
|
|
45
45
|
delegate :request, :response, to: :"runner.controller"
|
|
46
46
|
|
|
47
|
+
attr_reader :cookie_data, :header_data, :server_data
|
|
48
|
+
|
|
47
49
|
def initialize(runner)
|
|
48
50
|
@runner = runner
|
|
49
51
|
|
|
@@ -54,12 +56,23 @@ class TurboReflex::StateManager
|
|
|
54
56
|
@state = TurboReflex::State.new
|
|
55
57
|
end
|
|
56
58
|
|
|
59
|
+
# State the server used to render the page last time
|
|
60
|
+
cookie_state_hash = state.to_h
|
|
61
|
+
|
|
62
|
+
# State managed by the server on the backend (redis, postgres, msql, etc.)
|
|
63
|
+
# App specific, SEE: `TurboReflex::StateManager.state_override_block`
|
|
64
|
+
server_state_hash = {}
|
|
65
|
+
|
|
66
|
+
# State the client expects... related to optimistic UI updates
|
|
67
|
+
# i.e. Changes made on the client before making this request
|
|
68
|
+
header_state_hash = {}
|
|
69
|
+
|
|
57
70
|
# Apply server state overrides (i.e. state stored in databases like Redis, Postgres, etc...)
|
|
58
71
|
begin
|
|
59
72
|
state_override_block = self.class.state_override_block(runner.controller)
|
|
60
73
|
if state_override_block
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
server_state_hash = runner.controller.instance_eval(&state_override_block).with_indifferent_access
|
|
75
|
+
server_state_hash.each { |key, val| self[key] = val }
|
|
63
76
|
end
|
|
64
77
|
rescue => error
|
|
65
78
|
Rails.logger.error "Failed to apply `state_override_block` configured in #{runner.controller.class.name} to TurboReflex::State! #{error.message}"
|
|
@@ -70,11 +83,15 @@ class TurboReflex::StateManager
|
|
|
70
83
|
# This prevents race conditions (state mismatch) caused when frame and XHR requests emit immediately
|
|
71
84
|
# before the <meta id="turbo-reflex"> has been updated with the latest state from the server.
|
|
72
85
|
begin
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
header_state_hash = TurboReflex::State.deserialize_base64(header).with_indifferent_access
|
|
87
|
+
header_state_hash.each { |key, val| self[key] = val }
|
|
75
88
|
rescue => error
|
|
76
89
|
Rails.logger.error "Failed to apply client state from HTTP headers to TurboReflex::State! #{error.message}"
|
|
77
90
|
end
|
|
91
|
+
|
|
92
|
+
@cookie_data = cookie_state_hash
|
|
93
|
+
@header_data = header_state_hash
|
|
94
|
+
@server_data = server_state_hash
|
|
78
95
|
end
|
|
79
96
|
|
|
80
97
|
delegate :cache_key, :payload, to: :state
|
|
@@ -88,11 +105,11 @@ class TurboReflex::StateManager
|
|
|
88
105
|
state.write(*keys, value)
|
|
89
106
|
end
|
|
90
107
|
|
|
91
|
-
def
|
|
108
|
+
def write_cookie
|
|
92
109
|
return unless changed?
|
|
93
110
|
state.shrink!
|
|
94
111
|
state.prune! max_bytesize: TurboReflex::StateManager.cookie_max_bytesize
|
|
95
|
-
cookies["turbo_reflex.state"] = {value: state.ordinal_payload, path: "/", expires: 1.day.from_now}
|
|
112
|
+
cookies.signed["turbo_reflex.state"] = {value: state.ordinal_payload, path: "/", expires: 1.day.from_now}
|
|
96
113
|
changes_applied
|
|
97
114
|
end
|
|
98
115
|
|
|
@@ -112,6 +129,6 @@ class TurboReflex::StateManager
|
|
|
112
129
|
|
|
113
130
|
# State that the server last rendered with.
|
|
114
131
|
def cookie
|
|
115
|
-
cookies["turbo_reflex.state"]
|
|
132
|
+
cookies.signed["turbo_reflex.state"]
|
|
116
133
|
end
|
|
117
134
|
end
|
data/lib/turbo_reflex/version.rb
CHANGED
data/package.json
CHANGED