cable_ready 5.0.0 → 5.0.1
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 +7 -3
- data/app/assets/javascripts/cable_ready.js +49 -16
- data/app/assets/javascripts/cable_ready.min.js +2 -0
- data/app/assets/javascripts/cable_ready.min.js.map +1 -0
- data/app/assets/javascripts/cable_ready.umd.js +48 -16
- data/app/assets/javascripts/cable_ready.umd.min.js +2 -0
- data/app/assets/javascripts/cable_ready.umd.min.js.map +1 -0
- data/app/models/concerns/cable_ready/updatable.rb +3 -4
- data/cable_ready.gemspec~ +40 -0
- data/lib/cable_ready/config.rb +1 -1
- data/lib/cable_ready/engine.rb +4 -0
- data/lib/cable_ready/operation_builder.rb +6 -2
- data/lib/cable_ready/version.rb +1 -1
- data/package.json +2 -2
- data/yarn.lock +418 -61
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b867df19bb8d7a78152aa746001d00e593390055cbc7e673123d6e314d950a8a
|
|
4
|
+
data.tar.gz: c7c2bf1bbedd33b3af0de55dac46f2239a647357a1d6e671a57f6c3db5ef6e26
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f06c1061d2df7fee27d75a9a46714a27762486fe1d4d5dabc4fe6d6fc13a677e240a90f4c74bf4f3a0353a5b1f7d5335493cb90fe65428927236ed3155333c4d
|
|
7
|
+
data.tar.gz: c5efaaedebccbcb95f570e5d4ff122de9288edc923af7dd63434e7748ee4f34216552cb20921ac8755dfb2497f5f11cd3383414986ffbfaba0a6dd1150164bb5
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
cable_ready (5.0.
|
|
4
|
+
cable_ready (5.0.1)
|
|
5
5
|
actionpack (>= 5.2)
|
|
6
6
|
actionview (>= 5.2)
|
|
7
7
|
activesupport (>= 5.2)
|
|
@@ -108,9 +108,11 @@ GEM
|
|
|
108
108
|
net-smtp (0.3.3)
|
|
109
109
|
net-protocol
|
|
110
110
|
nio4r (2.5.8)
|
|
111
|
-
nokogiri (1.14.
|
|
111
|
+
nokogiri (1.14.3-arm64-darwin)
|
|
112
112
|
racc (~> 1.4)
|
|
113
|
-
nokogiri (1.14.
|
|
113
|
+
nokogiri (1.14.3-x86_64-darwin)
|
|
114
|
+
racc (~> 1.4)
|
|
115
|
+
nokogiri (1.14.3-x86_64-linux)
|
|
114
116
|
racc (~> 1.4)
|
|
115
117
|
parallel (1.22.1)
|
|
116
118
|
parser (3.2.1.0)
|
|
@@ -178,6 +180,7 @@ GEM
|
|
|
178
180
|
actionpack (>= 5.2)
|
|
179
181
|
activesupport (>= 5.2)
|
|
180
182
|
sprockets (>= 3.0.0)
|
|
183
|
+
sqlite3 (1.6.0-arm64-darwin)
|
|
181
184
|
sqlite3 (1.6.0-x86_64-darwin)
|
|
182
185
|
sqlite3 (1.6.0-x86_64-linux)
|
|
183
186
|
standard (1.19.1)
|
|
@@ -198,6 +201,7 @@ GEM
|
|
|
198
201
|
zeitwerk (2.6.7)
|
|
199
202
|
|
|
200
203
|
PLATFORMS
|
|
204
|
+
arm64-darwin-22
|
|
201
205
|
x86_64-darwin-19
|
|
202
206
|
x86_64-linux
|
|
203
207
|
|
|
@@ -2,7 +2,7 @@ import morphdom from "morphdom";
|
|
|
2
2
|
|
|
3
3
|
var name = "cable_ready";
|
|
4
4
|
|
|
5
|
-
var version = "5.0.
|
|
5
|
+
var version = "5.0.1";
|
|
6
6
|
|
|
7
7
|
var description = "CableReady helps you create great real-time user experiences by making it simple to trigger client-side DOM changes from server-side Ruby.";
|
|
8
8
|
|
|
@@ -59,7 +59,7 @@ var devDependencies = {
|
|
|
59
59
|
rollup: "^3.19.1",
|
|
60
60
|
sinon: "^15.0.2",
|
|
61
61
|
vite: "^4.1.4",
|
|
62
|
-
vitepress: "^1.0.0-
|
|
62
|
+
vitepress: "^1.0.0-beta.1",
|
|
63
63
|
"vitepress-plugin-search": "^1.0.4-alpha.19"
|
|
64
64
|
};
|
|
65
65
|
|
|
@@ -292,8 +292,29 @@ async function graciouslyFetch(url, additionalHeaders) {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
class BoundedQueue {
|
|
296
|
+
constructor(maxSize) {
|
|
297
|
+
this.maxSize = maxSize;
|
|
298
|
+
this.queue = [];
|
|
299
|
+
}
|
|
300
|
+
push(item) {
|
|
301
|
+
if (this.isFull()) {
|
|
302
|
+
// Remove the oldest item to make space for the new one
|
|
303
|
+
this.shift();
|
|
304
|
+
}
|
|
305
|
+
this.queue.push(item);
|
|
306
|
+
}
|
|
307
|
+
shift() {
|
|
308
|
+
return this.queue.shift();
|
|
309
|
+
}
|
|
310
|
+
isFull() {
|
|
311
|
+
return this.queue.length === this.maxSize;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
295
315
|
var utils = Object.freeze({
|
|
296
316
|
__proto__: null,
|
|
317
|
+
BoundedQueue: BoundedQueue,
|
|
297
318
|
after: after,
|
|
298
319
|
assignFocus: assignFocus,
|
|
299
320
|
before: before,
|
|
@@ -984,42 +1005,52 @@ var Debug = {
|
|
|
984
1005
|
|
|
985
1006
|
const request = (data, blocks) => {
|
|
986
1007
|
if (Debug.disabled) return;
|
|
987
|
-
|
|
1008
|
+
const message = `↑ Updatable request affecting ${blocks.length} element(s): `;
|
|
1009
|
+
console.log(message, {
|
|
988
1010
|
elements: blocks.map((b => b.element)),
|
|
989
1011
|
identifiers: blocks.map((b => b.element.getAttribute("identifier"))),
|
|
990
1012
|
data: data
|
|
991
1013
|
});
|
|
1014
|
+
return message;
|
|
992
1015
|
};
|
|
993
1016
|
|
|
994
1017
|
const cancel = (timestamp, reason) => {
|
|
995
1018
|
if (Debug.disabled) return;
|
|
996
1019
|
const duration = new Date - timestamp;
|
|
997
|
-
|
|
1020
|
+
const message = `❌ Updatable request canceled after ${duration}ms: ${reason}`;
|
|
1021
|
+
console.log(message);
|
|
1022
|
+
return message;
|
|
998
1023
|
};
|
|
999
1024
|
|
|
1000
1025
|
const response = (timestamp, element, urls) => {
|
|
1001
1026
|
if (Debug.disabled) return;
|
|
1002
1027
|
const duration = new Date - timestamp;
|
|
1003
|
-
|
|
1028
|
+
const message = `↓ Updatable response: All URLs fetched in ${duration}ms`;
|
|
1029
|
+
console.log(message, {
|
|
1004
1030
|
element: element,
|
|
1005
1031
|
urls: urls
|
|
1006
1032
|
});
|
|
1033
|
+
return message;
|
|
1007
1034
|
};
|
|
1008
1035
|
|
|
1009
1036
|
const morphStart = (timestamp, element) => {
|
|
1010
1037
|
if (Debug.disabled) return;
|
|
1011
1038
|
const duration = new Date - timestamp;
|
|
1012
|
-
|
|
1039
|
+
const message = `↻ Updatable morph: starting after ${duration}ms`;
|
|
1040
|
+
console.log(message, {
|
|
1013
1041
|
element: element
|
|
1014
1042
|
});
|
|
1043
|
+
return message;
|
|
1015
1044
|
};
|
|
1016
1045
|
|
|
1017
1046
|
const morphEnd = (timestamp, element) => {
|
|
1018
1047
|
if (Debug.disabled) return;
|
|
1019
1048
|
const duration = new Date - timestamp;
|
|
1020
|
-
|
|
1049
|
+
const message = `↺ Updatable morph: completed after ${duration}ms`;
|
|
1050
|
+
console.log(message, {
|
|
1021
1051
|
element: element
|
|
1022
1052
|
});
|
|
1053
|
+
return message;
|
|
1023
1054
|
};
|
|
1024
1055
|
|
|
1025
1056
|
var Log = {
|
|
@@ -1042,6 +1073,8 @@ class UpdatesForElement extends SubscribingElement {
|
|
|
1042
1073
|
mode: "open"
|
|
1043
1074
|
});
|
|
1044
1075
|
shadowRoot.innerHTML = template;
|
|
1076
|
+
this.triggerElementLog = new BoundedQueue(10);
|
|
1077
|
+
this.targetElementLog = new BoundedQueue(10);
|
|
1045
1078
|
}
|
|
1046
1079
|
async connectedCallback() {
|
|
1047
1080
|
if (this.preview) return;
|
|
@@ -1056,14 +1089,14 @@ class UpdatesForElement extends SubscribingElement {
|
|
|
1056
1089
|
async update(data) {
|
|
1057
1090
|
this.lastUpdateTimestamp = new Date;
|
|
1058
1091
|
const blocks = Array.from(document.querySelectorAll(this.query), (element => new Block(element))).filter((block => block.shouldUpdate(data)));
|
|
1059
|
-
Log.request(data, blocks);
|
|
1092
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.request(data, blocks)}`);
|
|
1060
1093
|
if (blocks.length === 0) {
|
|
1061
|
-
Log.cancel(this.lastUpdateTimestamp, "All elements filtered out");
|
|
1094
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.cancel(this.lastUpdateTimestamp, "All elements filtered out")}`);
|
|
1062
1095
|
return;
|
|
1063
1096
|
}
|
|
1064
1097
|
// first <cable-ready-updates-for> element in the DOM *at any given moment* updates all of the others
|
|
1065
1098
|
if (blocks[0].element !== this) {
|
|
1066
|
-
Log.cancel(this.lastUpdateTimestamp, "Update already requested");
|
|
1099
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.cancel(this.lastUpdateTimestamp, "Update already requested")}`);
|
|
1067
1100
|
return;
|
|
1068
1101
|
}
|
|
1069
1102
|
// hold a reference to the active element so that it can be restored after the morph
|
|
@@ -1079,7 +1112,7 @@ class UpdatesForElement extends SubscribingElement {
|
|
|
1079
1112
|
this.html[url] = await response.text();
|
|
1080
1113
|
}
|
|
1081
1114
|
})));
|
|
1082
|
-
Log.response(this.lastUpdateTimestamp, this, uniqueUrls);
|
|
1115
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.response(this.lastUpdateTimestamp, this, uniqueUrls)}`);
|
|
1083
1116
|
// track current block index for each URL; referred to as fragments
|
|
1084
1117
|
this.index = {};
|
|
1085
1118
|
blocks.forEach((block => {
|
|
@@ -1103,15 +1136,15 @@ class Block {
|
|
|
1103
1136
|
constructor(element) {
|
|
1104
1137
|
this.element = element;
|
|
1105
1138
|
}
|
|
1106
|
-
async process(data, html,
|
|
1107
|
-
const blockIndex =
|
|
1139
|
+
async process(data, html, fragmentsIndex, startTimestamp) {
|
|
1140
|
+
const blockIndex = fragmentsIndex[this.url];
|
|
1108
1141
|
const template = document.createElement("template");
|
|
1109
1142
|
this.element.setAttribute("updating", "updating");
|
|
1110
1143
|
template.innerHTML = String(html[this.url]).trim();
|
|
1111
1144
|
await this.resolveTurboFrames(template.content);
|
|
1112
1145
|
const fragments = template.content.querySelectorAll(this.query);
|
|
1113
1146
|
if (fragments.length <= blockIndex) {
|
|
1114
|
-
console.warn(`Update aborted due to insufficient number of elements. The offending url is ${this.url}
|
|
1147
|
+
console.warn(`Update aborted due to insufficient number of elements. The offending url is ${this.url}, the offending element is:`, this.element);
|
|
1115
1148
|
return;
|
|
1116
1149
|
}
|
|
1117
1150
|
const operation = {
|
|
@@ -1120,7 +1153,7 @@ class Block {
|
|
|
1120
1153
|
permanentAttributeName: "data-ignore-updates"
|
|
1121
1154
|
};
|
|
1122
1155
|
dispatch(this.element, "cable-ready:before-update", operation);
|
|
1123
|
-
Log.morphStart(startTimestamp, this.element);
|
|
1156
|
+
this.element.targetElementLog.push(`${(new Date).toLocaleString()}: ${Log.morphStart(startTimestamp, this.element)}`);
|
|
1124
1157
|
morphdom(this.element, fragments[blockIndex], {
|
|
1125
1158
|
childrenOnly: true,
|
|
1126
1159
|
onBeforeElUpdated: shouldMorph(operation),
|
|
@@ -1130,7 +1163,7 @@ class Block {
|
|
|
1130
1163
|
assignFocus(operation.focusSelector);
|
|
1131
1164
|
}
|
|
1132
1165
|
});
|
|
1133
|
-
Log.morphEnd(startTimestamp, this.element);
|
|
1166
|
+
this.element.targetElementLog.push(`${(new Date).toLocaleString()}: ${Log.morphEnd(startTimestamp, this.element)}`);
|
|
1134
1167
|
}
|
|
1135
1168
|
async resolveTurboFrames(documentFragment) {
|
|
1136
1169
|
const reloadingTurboFrames = [ ...documentFragment.querySelectorAll('turbo-frame[src]:not([loading="lazy"])') ];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"morphdom";var t="5.0.0-pre9";const n={INPUT:!0,TEXTAREA:!0,SELECT:!0},o={INPUT:!0,TEXTAREA:!0,OPTION:!0},r={"datetime-local":!0,"select-multiple":!0,"select-one":!0,color:!0,date:!0,datetime:!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,textarea:!0,time:!0,url:!0,week:!0};let s;var a={get element(){return s},set(e){s=e}};const i=e=>n[e.tagName]&&r[e.type],l=e=>{const t=(e&&e.nodeType===Node.ELEMENT_NODE?e:document.querySelector(e))||a.element;t&&t.focus&&t.focus()},c=(e,t,n={})=>{const o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o),window.jQuery&&window.jQuery(e).trigger(t,n)},u=e=>document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue,d=(e,t=!1)=>{const n=document.evaluate(e,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null),o=[];for(let e=0;e<n.snapshotLength;e++)o.push(n.snapshotItem(e));return t?o.reverse():o},m=e=>Array.from(e).flat(),h=(e,t)=>{Array.from(e.selectAll?e.element:[e.element]).forEach(t)},p=(f=function(e,t,n){return e+(n?"-":"")+t.toLowerCase()},function(e){return b(e).reduce(f,"")});var f;const b=e=>(e=null==e?"":e).match(/([A-Z]{2,}|[0-9]+|[A-Z]?[a-z]+|[A-Z])/g)||[],g=(e,t)=>!e.cancel&&(e.delay?setTimeout(t,e.delay):t(),!0),y=(e,t)=>c(e,`cable-ready:before-${p(t.operation)}`,t),w=(e,t)=>c(e,`cable-ready:after-${p(t.operation)}`,t);function E(e,t=250){let n;return(...o)=>{n&&clearTimeout(n),n=setTimeout((()=>e.apply(this,o)),t)}}function v(e){if(!e.ok)throw Error(e.statusText);return e}function A(e){return void 0===e||["string","number","boolean"].includes(typeof e)||console.warn(`Operation expects a string, number or boolean, but got ${e} (${typeof e})`),null!=e?e:""}function T(e){return void 0!==e&&"string"!=typeof e&&console.warn(`Operation expects a string, but got ${e} (${typeof e})`),null!=e?String(e):""}function S(e){return void 0===e||Array.isArray(e)||console.warn(`Operation expects an array, but got ${e} (${typeof e})`),null!=e?Array.from(e):[]}function C(e){return void 0!==e&&"object"!=typeof e&&console.warn(`Operation expects an object, but got ${e} (${typeof e})`),null!=e?Object(e):{}}function M(e){return void 0===e||Array.isArray(e)||"string"==typeof e||console.warn(`Operation expects an Array or a String, but got ${e} (${typeof e})`),null==e?"":Array.isArray(e)?Array.from(e):String(e)}async function x(e,t){try{const n=await fetch(e,{headers:{"X-REQUESTED-WITH":"XmlHttpRequest",...t}});if(null==n)return;return v(n),n}catch(t){console.error(`Could not fetch ${e}`)}}var O=Object.freeze({__proto__:null,after:w,assignFocus:l,before:y,debounce:E,dispatch:c,fragmentToString:function(e){return(new XMLSerializer).serializeToString(e)},getClassNames:m,graciouslyFetch:x,handleErrors:v,isTextInput:i,kebabize:p,operate:g,processElements:h,safeArray:S,safeObject:C,safeScalar:A,safeString:T,safeStringOrArray:M,xpathToElement:u,xpathToElementArray:d});const L=e=>(t,n)=>!q.map((o=>"function"!=typeof o||o(e,t,n))).includes(!1),R=e=>t=>{D.forEach((n=>{"function"==typeof n&&n(e,t)}))},$=(e,t,n)=>!(!o[t.tagName]&&t.isEqualNode(n)),U=(e,t,n)=>t!==a.element||!t.isContentEditable,k=(e,t,n)=>{const{permanentAttributeName:o}=e;if(!o)return!0;const r=t.closest(`[${o}]`);if(!r&&t===a.element&&i(t)){const e={value:!0};return Array.from(n.attributes).forEach((n=>{e[n.name]||t.setAttribute(n.name,n.value)})),!1}return!r},q=[$,k,U],D=[];var N=Object.freeze({__proto__:null,didMorph:R,didMorphCallbacks:D,shouldMorph:L,shouldMorphCallbacks:q,verifyNotContentEditable:U,verifyNotMutable:$,verifyNotPermanent:k}),P={append:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{html:n,focusSelector:o}=e;t.insertAdjacentHTML("beforeend",A(n)),l(o)})),w(t,e)}))},graft:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{parent:n,focusSelector:o}=e,r=document.querySelector(n);r&&(r.appendChild(t),l(o))})),w(t,e)}))},innerHtml:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{html:n,focusSelector:o}=e;t.innerHTML=A(n),l(o)})),w(t,e)}))},insertAdjacentHtml:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{html:n,position:o,focusSelector:r}=e;t.insertAdjacentHTML(o||"beforeend",A(n)),l(r)})),w(t,e)}))},insertAdjacentText:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{text:n,position:o,focusSelector:r}=e;t.insertAdjacentText(o||"beforeend",A(n)),l(r)})),w(t,e)}))},outerHtml:e=>{h(e,(t=>{const n=t.parentElement,o=n&&Array.from(n.children).indexOf(t);y(t,e),g(e,(()=>{const{html:n,focusSelector:o}=e;t.outerHTML=A(n),l(o)})),w(n?n.children[o]:document.documentElement,e)}))},prepend:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{html:n,focusSelector:o}=e;t.insertAdjacentHTML("afterbegin",A(n)),l(o)})),w(t,e)}))},remove:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{focusSelector:n}=e;t.remove(),l(n)})),w(document,e)}))},replace:e=>{h(e,(t=>{const n=t.parentElement,o=n&&Array.from(n.children).indexOf(t);y(t,e),g(e,(()=>{const{html:n,focusSelector:o}=e;t.outerHTML=A(n),l(o)})),w(n?n.children[o]:document.documentElement,e)}))},textContent:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{text:n,focusSelector:o}=e;t.textContent=A(n),l(o)})),w(t,e)}))},addCssClass:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n}=e;t.classList.add(...m([M(n)]))})),w(t,e)}))},removeAttribute:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n}=e;t.removeAttribute(T(n))})),w(t,e)}))},removeCssClass:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n}=e;t.classList.remove(...m([M(n)])),0===t.classList.length&&t.removeAttribute("class")})),w(t,e)}))},setAttribute:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n,value:o}=e;t.setAttribute(T(n),A(o))})),w(t,e)}))},setDatasetProperty:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n,value:o}=e;t.dataset[T(n)]=A(o)})),w(t,e)}))},setProperty:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n,value:o}=e;n in t&&(t[T(n)]=A(o))})),w(t,e)}))},setStyle:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n,value:o}=e;t.style[T(n)]=A(o)})),w(t,e)}))},setStyles:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{styles:n}=e;for(let[e,o]of Object.entries(n))t.style[T(e)]=A(o)})),w(t,e)}))},setValue:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{value:n}=e;t.value=A(n)})),w(t,e)}))},dispatchEvent:e=>{h(e,(t=>{y(t,e),g(e,(()=>{const{name:n,detail:o}=e;c(t,T(n),C(o))})),w(t,e)}))},setMeta:e=>{y(document,e),g(e,(()=>{const{name:t,content:n}=e;let o=document.head.querySelector(`meta[name='${t}']`);o||(o=document.createElement("meta"),o.name=T(t),document.head.appendChild(o)),o.content=A(n)})),w(document,e)},setTitle:e=>{y(document,e),g(e,(()=>{const{title:t}=e;document.title=A(t)})),w(document,e)},clearStorage:e=>{y(document,e),g(e,(()=>{const{type:t}=e;("session"===t?sessionStorage:localStorage).clear()})),w(document,e)},go:e=>{y(window,e),g(e,(()=>{const{delta:t}=e;history.go(t)})),w(window,e)},pushState:e=>{y(window,e),g(e,(()=>{const{state:t,title:n,url:o}=e;history.pushState(C(t),T(n),T(o))})),w(window,e)},redirectTo:e=>{y(window,e),g(e,(()=>{let{url:t,action:n,turbo:o}=e;n=n||"advance",t=T(t),void 0===o&&(o=!0),o?(window.Turbo&&window.Turbo.visit(t,{action:n}),window.Turbolinks&&window.Turbolinks.visit(t,{action:n}),window.Turbo||window.Turbolinks||(window.location.href=t)):window.location.href=t})),w(window,e)},reload:e=>{y(window,e),g(e,(()=>{window.location.reload()})),w(window,e)},removeStorageItem:e=>{y(document,e),g(e,(()=>{const{key:t,type:n}=e;("session"===n?sessionStorage:localStorage).removeItem(T(t))})),w(document,e)},replaceState:e=>{y(window,e),g(e,(()=>{const{state:t,title:n,url:o}=e;history.replaceState(C(t),T(n),T(o))})),w(window,e)},scrollIntoView:e=>{const{element:t}=e;y(t,e),g(e,(()=>{t.scrollIntoView(e)})),w(t,e)},setCookie:e=>{y(document,e),g(e,(()=>{const{cookie:t}=e;document.cookie=A(t)})),w(document,e)},setFocus:e=>{const{element:t}=e;y(t,e),g(e,(()=>{l(t)})),w(t,e)},setStorageItem:e=>{y(document,e),g(e,(()=>{const{key:t,value:n,type:o}=e;("session"===o?sessionStorage:localStorage).setItem(T(t),A(n))})),w(document,e)},consoleLog:e=>{y(document,e),g(e,(()=>{const{message:t,level:n}=e;n&&["warn","info","error"].includes(n)?console[n](t):console.log(t)})),w(document,e)},consoleTable:e=>{y(document,e),g(e,(()=>{const{data:t,columns:n}=e;console.table(t,S(n))})),w(document,e)},notification:e=>{y(document,e),g(e,(()=>{const{title:t,options:n}=e;Notification.requestPermission().then((o=>{e.permission=o,"granted"===o&&new Notification(T(t),C(n))}))})),w(document,e)},morph:t=>{h(t,(n=>{const{html:o}=t,r=document.createElement("template");r.innerHTML=String(A(o)).trim(),t.content=r.content;const s=n.parentElement,a=s&&Array.from(s.children).indexOf(n);y(n,t),g(t,(()=>{const{childrenOnly:o,focusSelector:s}=t;e(n,o?r.content:r.innerHTML,{childrenOnly:!!o,onBeforeElUpdated:L(t),onElUpdated:R(t)}),l(s)})),w(s?s.children[a]:document.documentElement,t)}))}};let H=P;const I=e=>{H={...H,...e}};var _={get all(){return H}};let j="warn";var z={get behavior(){return j},set(e){["warn","ignore","event","exception"].includes(e)?j=e:console.warn("Invalid 'onMissingElement' option. Defaulting to 'warn'.")}};const F=(e,t={onMissingElement:z.behavior})=>{const n={};e.forEach((e=>{e.batch&&(n[e.batch]=n[e.batch]?++n[e.batch]:1)})),e.forEach((e=>{const o=e.operation;try{if(e.selector?e.xpath?e.element=e.selectAll?d(e.selector):u(e.selector):e.element=e.selectAll?document.querySelectorAll(e.selector):document.querySelector(e.selector):e.element=document,e.element||"ignore"!==t.onMissingElement){a.set(document.activeElement);const t=_.all[o];t?(t(e),e.batch&&0==--n[e.batch]&&c(document,"cable-ready:batch-complete",{batch:e.batch})):console.error(`CableReady couldn't find the "${o}" operation. Make sure you use the camelized form when calling an operation method.`)}}catch(n){if(e.element)console.error(`CableReady detected an error in ${o||"operation"}: ${n.message}. If you need to support older browsers make sure you've included the corresponding polyfills. https://docs.stimulusreflex.com/setup#polyfills-for-ie11.`),console.error(n);else{const n=`CableReady ${o||""} operation failed due to missing DOM element for selector: '${e.selector}'`;switch(t.onMissingElement){case"ignore":break;case"event":c(document,"cable-ready:missing-element",{warning:n,operation:e});break;case"exception":throw n;default:console.warn(n)}}}}))};class X extends HTMLElement{disconnectedCallback(){this.channel&&this.channel.unsubscribe()}createSubscription(e,t,n){this.channel=e.subscriptions.create({channel:t,identifier:this.identifier},{received:n})}get preview(){return document.documentElement.hasAttribute("data-turbolinks-preview")||document.documentElement.hasAttribute("data-turbo-preview")}get identifier(){return this.getAttribute("identifier")}}let V;const Y=[25,50,75,100,200,250,500,800,1e3,2e3],Q=async(e=0)=>{if(V)return V;if(e>=Y.length)throw new Error("Couldn't obtain a Action Cable consumer within 5s");var t;return await(t=Y[e],new Promise((e=>setTimeout(e,t)))),await Q(e+1)};var Z={setConsumer(e){V=e},get consumer(){return V},getConsumer:async()=>await Q()};class B extends X{static define(){customElements.get("stream-from")||customElements.define("stream-from",this)}async connectedCallback(){if(this.preview)return;const e=await Z.getConsumer();e?this.createSubscription(e,"CableReady::Stream",this.performOperations.bind(this)):console.error("The `stream_from` helper cannot connect. You must initialize CableReady with an Action Cable consumer.")}performOperations(e){e.cableReady&&F(e.operations,{onMissingElement:this.onMissingElement})}get onMissingElement(){const e=this.getAttribute("missing")||z.behavior;return["warn","ignore","event"].includes(e)?e:(console.warn("Invalid 'missing' attribute. Defaulting to 'warn'."),"warn")}}let W=!1;var G={get enabled(){return W},get disabled(){return!W},get value(){return W},set(e){W=!!e},set debug(e){W=!!e}};var J=(e,t)=>{G.disabled||console.log(`↑ Updatable request affecting ${t.length} element(s): `,{elements:t.map((e=>e.element)),identifiers:t.map((e=>e.element.getAttribute("identifier"))),data:e})},K=(e,t)=>{if(G.disabled)return;const n=new Date-e;console.log(`❌ Updatable request canceled after ${n}ms: ${t}`)},ee=(e,t,n)=>{if(G.disabled)return;const o=new Date-e;console.log(`↓ Updatable response: All URLs fetched in ${o}ms`,{element:t,urls:n})},te=(e,t)=>{if(G.disabled)return;const n=new Date-e;console.log(`↻ Updatable morph: starting after ${n}ms`,{element:t})},ne=(e,t)=>{if(G.disabled)return;const n=new Date-e;console.log(`↺ Updatable morph: completed after ${n}ms`,{element:t})};class oe extends X{static define(){customElements.get("updates-for")||customElements.define("updates-for",this)}constructor(){super();this.attachShadow({mode:"open"}).innerHTML="\n<style>\n :host {\n display: block;\n }\n</style>\n<slot></slot>\n"}async connectedCallback(){if(this.preview)return;this.update=E(this.update.bind(this),this.debounce);const e=await Z.getConsumer();e?this.createSubscription(e,"CableReady::Stream",this.update):console.error("The `updates-for` helper cannot connect. You must initialize CableReady with an Action Cable consumer.")}async update(e){this.lastUpdateTimestamp=new Date;const t=Array.from(document.querySelectorAll(this.query),(e=>new re(e))).filter((t=>t.shouldUpdate(e)));if(J(e,t),0===t.length)return void K(this.lastUpdateTimestamp,"All elements filtered out");if(t[0].element!==this)return void K(this.lastUpdateTimestamp,"Update already requested");a.set(document.activeElement),this.html={};const n=[...new Set(t.map((e=>e.url)))];await Promise.all(n.map((async e=>{if(!this.html.hasOwnProperty(e)){const t=await x(e,{"X-Cable-Ready":"update"});this.html[e]=await t.text()}}))),ee(this.lastUpdateTimestamp,this,n),this.index={},t.forEach((t=>{this.index.hasOwnProperty(t.url)?this.index[t.url]++:this.index[t.url]=0,t.process(e,this.html,this.index,this.lastUpdateTimestamp)}))}get query(){return`updates-for[identifier="${this.identifier}"]`}get identifier(){return this.getAttribute("identifier")}get debounce(){return this.hasAttribute("debounce")?parseInt(this.getAttribute("debounce")):20}}class re{constructor(e){this.element=e}async process(t,n,o,r){const s=o[this.url],a=document.createElement("template");this.element.setAttribute("updating","updating"),a.innerHTML=String(n[this.url]).trim(),await this.resolveTurboFrames(a.content);const i=a.content.querySelectorAll(this.query);if(i.length<=s)return void console.warn(`Update aborted due to insufficient number of elements. The offending url is ${this.url}.`);const u={element:this.element,html:i[s],permanentAttributeName:"data-ignore-updates"};c(this.element,"cable-ready:before-update",u),te(r,this.element),e(this.element,i[s],{childrenOnly:!0,onBeforeElUpdated:L(u),onElUpdated:e=>{this.element.removeAttribute("updating"),c(this.element,"cable-ready:after-update",u),l(u.focusSelector)}}),ne(r,this.element)}async resolveTurboFrames(e){const t=[...e.querySelectorAll('turbo-frame[src]:not([loading="lazy"])')];return Promise.all(t.map((e=>new Promise((async t=>{const n=await x(e.getAttribute("src"),{"Turbo-Frame":e.id,"X-Cable-Ready":"update"}),o=document.createElement("template");o.innerHTML=await n.text(),await this.resolveTurboFrames(o.content);const r=`turbo-frame#${e.id}`,s=o.content.querySelector(r),a=s?s.innerHTML.trim():"";docFragment.querySelector(r).innerHTML=a,t()})))))}shouldUpdate(e){return!this.ignoresInnerUpdates&&this.hasChangesSelectedForUpdate(e)}hasChangesSelectedForUpdate(e){const t=this.element.getAttribute("only");return!(t&&e.changed&&!t.split(" ").some((t=>e.changed.includes(t))))}get ignoresInnerUpdates(){return this.element.hasAttribute("ignore-inner-updates")&&this.element.hasAttribute("performing-inner-update")}get url(){return this.element.hasAttribute("url")?this.element.getAttribute("url"):location.href}get identifier(){return this.element.identifier}get query(){return this.element.query}}const se=e=>{const t=e&&e.parentElement&&e.parentElement.closest("updates-for");t&&(t.setAttribute("performing-inner-update",""),se(t))},ae=e=>{const t=e&&e.parentElement&&e.parentElement.closest("updates-for");t&&(t.removeAttribute("performing-inner-update"),ae(t))},ie=()=>{document.addEventListener("stimulus-reflex:before",(e=>{se(e.detail.element)})),document.addEventListener("stimulus-reflex:after",(e=>{setTimeout((()=>{ae(e.detail.element)}))})),document.addEventListener("turbo:submit-start",(e=>{se(e.target)})),document.addEventListener("turbo:submit-end",(e=>{setTimeout((()=>{ae(e.target)}))})),document.addEventListener("turbo-boost:command:start",(e=>{se(e.target)})),document.addEventListener("turbo-boost:command:finish",(e=>{setTimeout((()=>{ae(e.target)}))})),document.addEventListener("turbo-boost:command:error",(e=>{setTimeout((()=>{ae(e.target)}))})),B.define(),oe.define()},le={perform:F,performAsync:(e,t={onMissingElement:z.behavior})=>new Promise(((n,o)=>{try{n(F(e,t))}catch(e){o(e)}})),shouldMorphCallbacks:q,didMorphCallbacks:D,initialize:(e={})=>{const{consumer:t,onMissingElement:n,debug:o}=e;G.set(!!o),t?Z.setConsumer(t):console.error("CableReady requires a reference to your Action Cable `consumer` for its helpers to function.\nEnsure that you have imported the `CableReady` package as well as `consumer` from your `channels` folder, then call `CableReady.initialize({ consumer })`."),n&&MissingElement.set(n),ie()},addOperation:(e,t)=>{const n={};n[e]=t,I(n)},addOperations:e=>{I(e)},version:t,cable:Z,get DOMOperations(){return console.warn("DEPRECATED: Please use `CableReady.operations` instead of `CableReady.DOMOperations`"),_.all},get operations(){return _.all},get consumer(){return Z.consumer}};window.CableReady=le;export{N as MorphCallbacks,B as StreamFromElement,X as SubscribingElement,oe as UpdatesForElement,O as Utils,le as default};
|
|
2
|
+
//# sourceMappingURL=cable_ready.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cable_ready.min.js","sources":["../../../javascript/enums.js","../../../javascript/active_element.js","../../../javascript/utils.js","../../../javascript/morph_callbacks.js","../../../javascript/operations.js","../../../javascript/operation_store.js","../../../javascript/missing_element.js","../../../javascript/cable_ready.js","../../../javascript/elements/subscribing_element.js","../../../javascript/cable_consumer.js","../../../javascript/elements/stream_from_element.js","../../../javascript/debug.js","../../../javascript/updatable/log.js","../../../javascript/elements/updates_for_element.js","../../../javascript/updatable/inner_updates_compat.js","../../../javascript/elements/index.js","../../../javascript/index.js"],"sourcesContent":["export const inputTags = {\n INPUT: true,\n TEXTAREA: true,\n SELECT: true\n}\n\nexport const mutableTags = {\n INPUT: true,\n TEXTAREA: true,\n OPTION: true\n}\n\nexport const textInputTypes = {\n 'datetime-local': true,\n 'select-multiple': true,\n 'select-one': true,\n color: true,\n date: true,\n datetime: true,\n email: true,\n month: true,\n number: true,\n password: true,\n range: true,\n search: true,\n tel: true,\n text: true,\n textarea: true,\n time: true,\n url: true,\n week: true\n}\n","let activeElement\n\nexport default {\n get element () {\n return activeElement\n },\n set (element) {\n activeElement = element\n }\n}\n","import { inputTags, textInputTypes } from './enums'\nimport ActiveElement from './active_element'\n\n// Indicates if the passed element is considered a text input.\n//\nconst isTextInput = element => {\n return inputTags[element.tagName] && textInputTypes[element.type]\n}\n\n// Assigns focus to the appropriate element... preferring the explicitly passed selector\n//\n// * selector - a CSS selector for the element that should have focus\n//\nconst assignFocus = selector => {\n const element =\n selector && selector.nodeType === Node.ELEMENT_NODE\n ? selector\n : document.querySelector(selector)\n const focusElement = element || ActiveElement.element\n if (focusElement && focusElement.focus) focusElement.focus()\n}\n\n// Dispatches an event on the passed element\n//\n// * element - the element\n// * name - the name of the event\n// * detail - the event detail\n//\nconst dispatch = (element, name, detail = {}) => {\n const init = { bubbles: true, cancelable: true, detail }\n const event = new CustomEvent(name, init)\n element.dispatchEvent(event)\n if (window.jQuery) window.jQuery(element).trigger(name, detail)\n}\n\n// Accepts an xPath query and returns the element found at that position in the DOM\n//\nconst xpathToElement = xpath => {\n return document.evaluate(\n xpath,\n document,\n null,\n XPathResult.FIRST_ORDERED_NODE_TYPE,\n null\n ).singleNodeValue\n}\n\n// Accepts an xPath query and returns all matching elements in the DOM\n//\nconst xpathToElementArray = (xpath, reverse = false) => {\n const snapshotList = document.evaluate(\n xpath,\n document,\n null,\n XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,\n null\n )\n const snapshots = []\n\n for (let i = 0; i < snapshotList.snapshotLength; i++) {\n snapshots.push(snapshotList.snapshotItem(i))\n }\n\n return reverse ? snapshots.reverse() : snapshots\n}\n\n// Return an array with the class names to be used\n//\n// * names - could be a string or an array of strings for multiple classes.\n//\nconst getClassNames = names => Array.from(names).flat()\n\n// Perform operation for either the first or all of the elements returned by CSS selector\n//\n// * operation - the instruction payload from perform\n// * callback - the operation function to run for each element\n//\nconst processElements = (operation, callback) => {\n Array.from(\n operation.selectAll ? operation.element : [operation.element]\n ).forEach(callback)\n}\n\n// convert string to kebab-case\n// most other implementations (lodash) are focused on camelCase to kebab-case\n// instead, this uses word token boundaries to produce readable URL slugs and keys\n// this implementation will not support Emoji or other non-ASCII characters\n//\nconst kebabize = createCompounder(function (result, word, index) {\n return result + (index ? '-' : '') + word.toLowerCase()\n})\n\nfunction createCompounder (callback) {\n return function (str) {\n return words(str).reduce(callback, '')\n }\n}\n\nconst words = str => {\n str = str == null ? '' : str\n return str.match(/([A-Z]{2,}|[0-9]+|[A-Z]?[a-z]+|[A-Z])/g) || []\n}\n\n// Provide a standardized pipeline of checks and modifications to all operations based on provided options\n// Currently skips execution if cancelled and implements an optional delay\n//\nconst operate = (operation, callback) => {\n if (!operation.cancel) {\n operation.delay ? setTimeout(callback, operation.delay) : callback()\n return true\n }\n return false\n}\n\n// Dispatch life-cycle events with standardized naming\nconst before = (target, operation) =>\n dispatch(\n target,\n `cable-ready:before-${kebabize(operation.operation)}`,\n operation\n )\n\nconst after = (target, operation) =>\n dispatch(\n target,\n `cable-ready:after-${kebabize(operation.operation)}`,\n operation\n )\n\nfunction debounce (fn, delay = 250) {\n let timer\n return (...args) => {\n const callback = () => fn.apply(this, args)\n if (timer) clearTimeout(timer)\n timer = setTimeout(callback, delay)\n }\n}\n\nfunction handleErrors (response) {\n if (!response.ok) throw Error(response.statusText)\n return response\n}\n\nfunction safeScalar (val) {\n if (\n val !== undefined &&\n !['string', 'number', 'boolean'].includes(typeof val)\n )\n console.warn(\n `Operation expects a string, number or boolean, but got ${val} (${typeof val})`\n )\n return val != null ? val : ''\n}\n\nfunction safeString (str) {\n if (str !== undefined && typeof str !== 'string')\n console.warn(`Operation expects a string, but got ${str} (${typeof str})`)\n\n return str != null ? String(str) : ''\n}\n\nfunction safeArray (arr) {\n if (arr !== undefined && !Array.isArray(arr))\n console.warn(`Operation expects an array, but got ${arr} (${typeof arr})`)\n return arr != null ? Array.from(arr) : []\n}\n\nfunction safeObject (obj) {\n if (obj !== undefined && typeof obj !== 'object')\n console.warn(`Operation expects an object, but got ${obj} (${typeof obj})`)\n return obj != null ? Object(obj) : {}\n}\n\nfunction safeStringOrArray (elem) {\n if (elem !== undefined && !Array.isArray(elem) && typeof elem !== 'string')\n console.warn(`Operation expects an Array or a String, but got ${elem} (${typeof elem})`)\n\n return elem == null ? '' : Array.isArray(elem) ? Array.from(elem) : String(elem)\n}\n\nfunction fragmentToString (fragment) {\n return new XMLSerializer().serializeToString(fragment)\n}\n\n// A proxy method to wrap a fetch call in error handling\n//\n// * url - the URL to fetch\n// * additionalHeaders - an object of additional headers passed to fetch\n//\nasync function graciouslyFetch (url, additionalHeaders) {\n try {\n const response = await fetch(url, {\n headers: {\n 'X-REQUESTED-WITH': 'XmlHttpRequest',\n ...additionalHeaders\n }\n })\n if (response == undefined) return\n\n handleErrors(response)\n\n return response\n } catch (e) {\n console.error(`Could not fetch ${url}`)\n }\n}\n\nexport {\n isTextInput,\n assignFocus,\n dispatch,\n xpathToElement,\n xpathToElementArray,\n getClassNames,\n processElements,\n operate,\n before,\n after,\n debounce,\n handleErrors,\n graciouslyFetch,\n kebabize,\n safeScalar,\n safeString,\n safeArray,\n safeObject,\n safeStringOrArray,\n fragmentToString\n}\n","import { mutableTags } from './enums'\nimport { isTextInput } from './utils'\nimport ActiveElement from './active_element'\n\n// Indicates whether or not we should morph an element via onBeforeElUpdated callback\n// SEE: https://github.com/patrick-steele-idem/morphdom#morphdomfromnode-tonode-options--node\n//\nconst shouldMorph = operation => (fromEl, toEl) => {\n return !shouldMorphCallbacks\n .map(callback => {\n return typeof callback === 'function'\n ? callback(operation, fromEl, toEl)\n : true\n })\n .includes(false)\n}\n\n// Execute any pluggable functions that modify elements after morphing via onElUpdated callback\n//\nconst didMorph = operation => el => {\n didMorphCallbacks.forEach(callback => {\n if (typeof callback === 'function') callback(operation, el)\n })\n}\n\nconst verifyNotMutable = (detail, fromEl, toEl) => {\n // Skip nodes that are equal:\n // https://github.com/patrick-steele-idem/morphdom#can-i-make-morphdom-blaze-through-the-dom-tree-even-faster-yes\n if (!mutableTags[fromEl.tagName] && fromEl.isEqualNode(toEl)) return false\n return true\n}\n\nconst verifyNotContentEditable = (detail, fromEl, toEl) => {\n if (fromEl === ActiveElement.element && fromEl.isContentEditable) return false\n return true\n}\n\nconst verifyNotPermanent = (detail, fromEl, toEl) => {\n const { permanentAttributeName } = detail\n if (!permanentAttributeName) return true\n\n const permanent = fromEl.closest(`[${permanentAttributeName}]`)\n\n // only morph attributes on the active non-permanent text input\n if (!permanent && fromEl === ActiveElement.element && isTextInput(fromEl)) {\n const ignore = { value: true }\n Array.from(toEl.attributes).forEach(attribute => {\n if (!ignore[attribute.name])\n fromEl.setAttribute(attribute.name, attribute.value)\n })\n return false\n }\n\n return !permanent\n}\n\nconst shouldMorphCallbacks = [\n verifyNotMutable,\n verifyNotPermanent,\n verifyNotContentEditable\n]\nconst didMorphCallbacks = []\n\nexport {\n shouldMorphCallbacks,\n didMorphCallbacks,\n shouldMorph,\n didMorph,\n verifyNotMutable,\n verifyNotContentEditable,\n verifyNotPermanent\n}\n","import morphdom from 'morphdom'\n\nimport { shouldMorph, didMorph } from './morph_callbacks'\nimport {\n assignFocus,\n dispatch,\n getClassNames,\n processElements,\n before,\n after,\n operate,\n safeScalar,\n safeString,\n safeArray,\n safeObject,\n safeStringOrArray\n} from './utils'\n\nexport default {\n // DOM Mutations\n\n append: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { html, focusSelector } = operation\n element.insertAdjacentHTML('beforeend', safeScalar(html))\n assignFocus(focusSelector)\n })\n after(element, operation)\n })\n },\n\n graft: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { parent, focusSelector } = operation\n const parentElement = document.querySelector(parent)\n if (parentElement) {\n parentElement.appendChild(element)\n assignFocus(focusSelector)\n }\n })\n after(element, operation)\n })\n },\n\n innerHtml: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { html, focusSelector } = operation\n element.innerHTML = safeScalar(html)\n assignFocus(focusSelector)\n })\n after(element, operation)\n })\n },\n\n insertAdjacentHtml: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { html, position, focusSelector } = operation\n element.insertAdjacentHTML(position || 'beforeend', safeScalar(html))\n assignFocus(focusSelector)\n })\n after(element, operation)\n })\n },\n\n insertAdjacentText: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { text, position, focusSelector } = operation\n element.insertAdjacentText(position || 'beforeend', safeScalar(text))\n assignFocus(focusSelector)\n })\n after(element, operation)\n })\n },\n\n outerHtml: operation => {\n processElements(operation, element => {\n const parent = element.parentElement\n const idx = parent && Array.from(parent.children).indexOf(element)\n before(element, operation)\n operate(operation, () => {\n const { html, focusSelector } = operation\n element.outerHTML = safeScalar(html)\n assignFocus(focusSelector)\n })\n after(parent ? parent.children[idx] : document.documentElement, operation)\n })\n },\n\n prepend: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { html, focusSelector } = operation\n element.insertAdjacentHTML('afterbegin', safeScalar(html))\n assignFocus(focusSelector)\n })\n after(element, operation)\n })\n },\n\n remove: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { focusSelector } = operation\n element.remove()\n assignFocus(focusSelector)\n })\n after(document, operation)\n })\n },\n\n replace: operation => {\n processElements(operation, element => {\n const parent = element.parentElement\n const idx = parent && Array.from(parent.children).indexOf(element)\n before(element, operation)\n operate(operation, () => {\n const { html, focusSelector } = operation\n element.outerHTML = safeScalar(html)\n assignFocus(focusSelector)\n })\n after(parent ? parent.children[idx] : document.documentElement, operation)\n })\n },\n\n textContent: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { text, focusSelector } = operation\n element.textContent = safeScalar(text)\n assignFocus(focusSelector)\n })\n after(element, operation)\n })\n },\n\n // Element Property Mutations\n\n addCssClass: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name } = operation\n element.classList.add(...getClassNames([safeStringOrArray(name)]))\n })\n after(element, operation)\n })\n },\n\n removeAttribute: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name } = operation\n element.removeAttribute(safeString(name))\n })\n after(element, operation)\n })\n },\n\n removeCssClass: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name } = operation\n element.classList.remove(...getClassNames([safeStringOrArray(name)]))\n if (element.classList.length === 0) element.removeAttribute('class')\n })\n after(element, operation)\n })\n },\n\n setAttribute: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name, value } = operation\n element.setAttribute(safeString(name), safeScalar(value))\n })\n after(element, operation)\n })\n },\n\n setDatasetProperty: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name, value } = operation\n element.dataset[safeString(name)] = safeScalar(value)\n })\n after(element, operation)\n })\n },\n\n setProperty: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name, value } = operation\n if (name in element) element[safeString(name)] = safeScalar(value)\n })\n after(element, operation)\n })\n },\n\n setStyle: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name, value } = operation\n element.style[safeString(name)] = safeScalar(value)\n })\n after(element, operation)\n })\n },\n\n setStyles: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { styles } = operation\n for (let [name, value] of Object.entries(styles))\n element.style[safeString(name)] = safeScalar(value)\n })\n after(element, operation)\n })\n },\n\n setValue: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { value } = operation\n element.value = safeScalar(value)\n })\n after(element, operation)\n })\n },\n\n // DOM Events and Meta-Operations\n\n dispatchEvent: operation => {\n processElements(operation, element => {\n before(element, operation)\n operate(operation, () => {\n const { name, detail } = operation\n dispatch(element, safeString(name), safeObject(detail))\n })\n after(element, operation)\n })\n },\n\n setMeta: operation => {\n before(document, operation)\n operate(operation, () => {\n const { name, content } = operation\n let meta = document.head.querySelector(`meta[name='${name}']`)\n if (!meta) {\n meta = document.createElement('meta')\n meta.name = safeString(name)\n document.head.appendChild(meta)\n }\n meta.content = safeScalar(content)\n })\n after(document, operation)\n },\n\n setTitle: operation => {\n before(document, operation)\n operate(operation, () => {\n const { title } = operation\n document.title = safeScalar(title)\n })\n after(document, operation)\n },\n\n // Browser Manipulations\n\n clearStorage: operation => {\n before(document, operation)\n operate(operation, () => {\n const { type } = operation\n const storage = type === 'session' ? sessionStorage : localStorage\n storage.clear()\n })\n after(document, operation)\n },\n\n go: operation => {\n before(window, operation)\n operate(operation, () => {\n const { delta } = operation\n history.go(delta)\n })\n after(window, operation)\n },\n\n pushState: operation => {\n before(window, operation)\n operate(operation, () => {\n const { state, title, url } = operation\n history.pushState(safeObject(state), safeString(title), safeString(url))\n })\n after(window, operation)\n },\n\n redirectTo: operation => {\n before(window, operation)\n operate(operation, () => {\n let { url, action, turbo } = operation\n action = action || 'advance'\n url = safeString(url)\n if (turbo === undefined) turbo = true\n\n if (turbo) {\n if (window.Turbo) window.Turbo.visit(url, { action })\n if (window.Turbolinks) window.Turbolinks.visit(url, { action })\n if (!window.Turbo && !window.Turbolinks) window.location.href = url\n } else {\n window.location.href = url\n }\n })\n after(window, operation)\n },\n\n reload: operation => {\n before(window, operation)\n operate(operation, () => {\n window.location.reload()\n })\n after(window, operation)\n },\n\n removeStorageItem: operation => {\n before(document, operation)\n operate(operation, () => {\n const { key, type } = operation\n const storage = type === 'session' ? sessionStorage : localStorage\n storage.removeItem(safeString(key))\n })\n after(document, operation)\n },\n\n replaceState: operation => {\n before(window, operation)\n operate(operation, () => {\n const { state, title, url } = operation\n history.replaceState(\n safeObject(state),\n safeString(title),\n safeString(url)\n )\n })\n after(window, operation)\n },\n\n scrollIntoView: operation => {\n const { element } = operation\n before(element, operation)\n operate(operation, () => {\n element.scrollIntoView(operation)\n })\n after(element, operation)\n },\n\n setCookie: operation => {\n before(document, operation)\n operate(operation, () => {\n const { cookie } = operation\n document.cookie = safeScalar(cookie)\n })\n after(document, operation)\n },\n\n setFocus: operation => {\n const { element } = operation\n before(element, operation)\n operate(operation, () => {\n assignFocus(element)\n })\n after(element, operation)\n },\n\n setStorageItem: operation => {\n before(document, operation)\n operate(operation, () => {\n const { key, value, type } = operation\n const storage = type === 'session' ? sessionStorage : localStorage\n storage.setItem(safeString(key), safeScalar(value))\n })\n after(document, operation)\n },\n\n // Notifications\n\n consoleLog: operation => {\n before(document, operation)\n operate(operation, () => {\n const { message, level } = operation\n level && ['warn', 'info', 'error'].includes(level)\n ? console[level](message)\n : console.log(message)\n })\n after(document, operation)\n },\n\n consoleTable: operation => {\n before(document, operation)\n operate(operation, () => {\n const { data, columns } = operation\n console.table(data, safeArray(columns))\n })\n after(document, operation)\n },\n\n notification: operation => {\n before(document, operation)\n operate(operation, () => {\n const { title, options } = operation\n Notification.requestPermission().then(result => {\n operation.permission = result\n if (result === 'granted')\n new Notification(safeString(title), safeObject(options))\n })\n })\n after(document, operation)\n },\n\n // Morph operations\n\n morph: operation => {\n processElements(operation, element => {\n const { html } = operation\n const template = document.createElement('template')\n template.innerHTML = String(safeScalar(html)).trim()\n operation.content = template.content\n const parent = element.parentElement\n const idx = parent && Array.from(parent.children).indexOf(element)\n before(element, operation)\n operate(operation, () => {\n const { childrenOnly, focusSelector } = operation\n morphdom(\n element,\n childrenOnly ? template.content : template.innerHTML,\n {\n childrenOnly: !!childrenOnly,\n onBeforeElUpdated: shouldMorph(operation),\n onElUpdated: didMorph(operation)\n }\n )\n assignFocus(focusSelector)\n })\n after(parent ? parent.children[idx] : document.documentElement, operation)\n })\n }\n}\n","import Operations from './operations'\n\nlet operations = Operations\n\nconst add = newOperations => {\n operations = { ...operations, ...newOperations }\n}\n\nconst addOperations = operations => {\n add(operations)\n}\n\nconst addOperation = (name, operation) => {\n const operations = {}\n operations[name] = operation\n\n add(operations)\n}\n\nexport { addOperation, addOperations }\n\nexport default {\n get all () {\n return operations\n }\n}\n","let missingElement = 'warn'\n\nexport default {\n get behavior () {\n return missingElement\n },\n set (value) {\n if (['warn', 'ignore', 'event', 'exception'].includes(value))\n missingElement = value\n else\n console.warn(\"Invalid 'onMissingElement' option. Defaulting to 'warn'.\")\n }\n}\n","import { xpathToElement, xpathToElementArray, dispatch } from './utils'\nimport ActiveElement from './active_element'\nimport OperationStore from './operation_store'\nimport MissingElement from './missing_element'\n\nconst perform = (\n operations,\n options = { onMissingElement: MissingElement.behavior }\n) => {\n const batches = {}\n operations.forEach(operation => {\n if (!!operation.batch)\n batches[operation.batch] = batches[operation.batch]\n ? ++batches[operation.batch]\n : 1\n })\n operations.forEach(operation => {\n const name = operation.operation\n try {\n if (operation.selector) {\n if (operation.xpath) {\n operation.element = operation.selectAll\n ? xpathToElementArray(operation.selector)\n : xpathToElement(operation.selector)\n } else {\n operation.element = operation.selectAll\n ? document.querySelectorAll(operation.selector)\n : document.querySelector(operation.selector)\n }\n } else {\n operation.element = document\n }\n if (operation.element || options.onMissingElement !== 'ignore') {\n ActiveElement.set(document.activeElement)\n const cableReadyOperation = OperationStore.all[name]\n\n if (cableReadyOperation) {\n cableReadyOperation(operation)\n if (!!operation.batch && --batches[operation.batch] === 0)\n dispatch(document, 'cable-ready:batch-complete', {\n batch: operation.batch\n })\n } else {\n console.error(\n `CableReady couldn't find the \"${name}\" operation. Make sure you use the camelized form when calling an operation method.`\n )\n }\n }\n } catch (e) {\n if (operation.element) {\n console.error(\n `CableReady detected an error in ${name || 'operation'}: ${\n e.message\n }. If you need to support older browsers make sure you've included the corresponding polyfills. https://docs.stimulusreflex.com/setup#polyfills-for-ie11.`\n )\n console.error(e)\n } else {\n const warning = `CableReady ${name ||\n ''} operation failed due to missing DOM element for selector: '${\n operation.selector\n }'`\n switch (options.onMissingElement) {\n case 'ignore':\n break\n case 'event':\n dispatch(document, 'cable-ready:missing-element', {\n warning,\n operation\n })\n break\n case 'exception':\n throw warning\n default:\n console.warn(warning)\n }\n }\n }\n })\n}\n\nconst performAsync = (\n operations,\n options = { onMissingElement: MissingElement.behavior }\n) => {\n return new Promise((resolve, reject) => {\n try {\n resolve(perform(operations, options))\n } catch (err) {\n reject(err)\n }\n })\n}\n\nexport { perform, performAsync }\n","export default class SubscribingElement extends HTMLElement {\n disconnectedCallback () {\n if (this.channel) this.channel.unsubscribe()\n }\n\n createSubscription (consumer, channel, receivedCallback) {\n this.channel = consumer.subscriptions.create(\n {\n channel,\n identifier: this.identifier\n },\n {\n received: receivedCallback\n }\n )\n }\n\n get preview () {\n return (\n document.documentElement.hasAttribute('data-turbolinks-preview') ||\n document.documentElement.hasAttribute('data-turbo-preview')\n )\n }\n\n get identifier () {\n return this.getAttribute('identifier')\n }\n}\n","let consumer\n\nconst BACKOFF = [25, 50, 75, 100, 200, 250, 500, 800, 1000, 2000]\n\nconst wait = (ms) => new Promise(resolve => setTimeout(resolve, ms))\n\nconst getConsumerWithRetry = async (retry = 0) => {\n if (consumer) return consumer\n\n if (retry >= BACKOFF.length) {\n throw new Error(\"Couldn't obtain a Action Cable consumer within 5s\")\n }\n\n await wait(BACKOFF[retry])\n\n return await getConsumerWithRetry(retry + 1)\n}\n\nexport default {\n setConsumer (value) {\n consumer = value\n },\n\n get consumer () {\n return consumer\n },\n\n async getConsumer () {\n return await getConsumerWithRetry()\n }\n}\n","import { perform } from '../cable_ready'\nimport SubscribingElement from './subscribing_element'\nimport CableConsumer from '../cable_consumer'\nimport MissingElement from '../missing_element'\n\nexport default class StreamFromElement extends SubscribingElement {\n static define () {\n if (!customElements.get('stream-from')) {\n customElements.define('stream-from', this)\n }\n }\n\n async connectedCallback () {\n if (this.preview) return\n\n const consumer = await CableConsumer.getConsumer()\n\n if (consumer) {\n this.createSubscription(\n consumer,\n 'CableReady::Stream',\n this.performOperations.bind(this)\n )\n } else {\n console.error(\n 'The `stream_from` helper cannot connect. You must initialize CableReady with an Action Cable consumer.'\n )\n }\n }\n\n performOperations (data) {\n if (data.cableReady)\n perform(data.operations, { onMissingElement: this.onMissingElement })\n }\n\n get onMissingElement () {\n const value = this.getAttribute('missing') || MissingElement.behavior\n\n // stream_from does not support raising exceptions on missing elements because there's no way to catch them\n if (['warn', 'ignore', 'event'].includes(value)) return value\n else {\n console.warn(\"Invalid 'missing' attribute. Defaulting to 'warn'.\")\n return 'warn'\n }\n }\n}\n","let debugging = false\n\nexport default {\n get enabled () {\n return debugging\n },\n get disabled () {\n return !debugging\n },\n get value () {\n return debugging\n },\n set (value) {\n debugging = !!value\n },\n set debug (value) {\n debugging = !!value\n }\n}\n","import Debug from '../debug'\n\nconst request = (data, blocks) => {\n if (Debug.disabled) return\n\n console.log(\n `\\u2191 Updatable request affecting ${blocks.length} element(s): `,\n {\n elements: blocks.map(b => b.element),\n identifiers: blocks.map(b => b.element.getAttribute('identifier')),\n data\n }\n )\n}\n\nconst cancel = (timestamp, reason) => {\n if (Debug.disabled) return\n\n const duration = new Date() - timestamp\n console.log(\n `\\u274C Updatable request canceled after ${duration}ms: ${reason}`\n )\n}\n\nconst response = (timestamp, element, urls) => {\n if (Debug.disabled) return\n\n const duration = new Date() - timestamp\n console.log(`\\u2193 Updatable response: All URLs fetched in ${duration}ms`, {\n element,\n urls\n })\n}\n\nconst morphStart = (timestamp, element) => {\n if (Debug.disabled) return\n\n const duration = new Date() - timestamp\n console.log(`\\u21BB Updatable morph: starting after ${duration}ms`, {\n element\n })\n}\n\nconst morphEnd = (timestamp, element) => {\n if (Debug.disabled) return\n\n const duration = new Date() - timestamp\n console.log(`\\u21BA Updatable morph: completed after ${duration}ms`, {\n element\n })\n}\n\nexport default { request, cancel, response, morphStart, morphEnd }\n","import morphdom from 'morphdom'\nimport SubscribingElement from './subscribing_element'\n\nimport { shouldMorph } from '../morph_callbacks'\nimport { debounce, assignFocus, dispatch, graciouslyFetch } from '../utils'\n\nimport ActiveElement from '../active_element'\nimport CableConsumer from '../cable_consumer'\nimport Log from '../updatable/log'\n\nconst template = `\n<style>\n :host {\n display: block;\n }\n</style>\n<slot></slot>\n`\n\nfunction url (element) {\n return element.hasAttribute('url')\n ? element.getAttribute('url')\n : location.href\n}\n\nexport default class UpdatesForElement extends SubscribingElement {\n static define () {\n if (!customElements.get('updates-for')) {\n customElements.define('updates-for', this)\n }\n }\n\n constructor () {\n super()\n const shadowRoot = this.attachShadow({ mode: 'open' })\n shadowRoot.innerHTML = template\n }\n\n async connectedCallback () {\n if (this.preview) return\n this.update = debounce(this.update.bind(this), this.debounce)\n\n const consumer = await CableConsumer.getConsumer()\n\n if (consumer) {\n this.createSubscription(consumer, 'CableReady::Stream', this.update)\n } else {\n console.error(\n 'The `updates-for` helper cannot connect. You must initialize CableReady with an Action Cable consumer.'\n )\n }\n }\n\n async update (data) {\n this.lastUpdateTimestamp = new Date()\n\n const blocks = Array.from(\n document.querySelectorAll(this.query),\n element => new Block(element)\n ).filter(block => block.shouldUpdate(data))\n\n Log.request(data, blocks)\n\n if (blocks.length === 0) {\n Log.cancel(this.lastUpdateTimestamp, 'All elements filtered out')\n\n return\n }\n\n // first updates-for element in the DOM *at any given moment* updates all of the others\n if (blocks[0].element !== this) {\n Log.cancel(this.lastUpdateTimestamp, 'Update already requested')\n\n return\n }\n\n // hold a reference to the active element so that it can be restored after the morph\n ActiveElement.set(document.activeElement)\n\n // store all retrieved HTML in an object keyed by URL to minimize fetch calls\n this.html = {}\n\n const uniqueUrls = [...new Set(blocks.map(block => block.url))]\n\n await Promise.all(\n uniqueUrls.map(async url => {\n if (!this.html.hasOwnProperty(url)) {\n const response = await graciouslyFetch(url, {\n 'X-Cable-Ready': 'update'\n })\n this.html[url] = await response.text()\n }\n })\n )\n\n Log.response(this.lastUpdateTimestamp, this, uniqueUrls)\n\n // track current block index for each URL; referred to as fragments\n this.index = {}\n\n blocks.forEach(block => {\n // if the block's URL is not in the index, initialize it to 0; otherwise, increment it\n this.index.hasOwnProperty(block.url)\n ? this.index[block.url]++\n : (this.index[block.url] = 0)\n\n block.process(data, this.html, this.index, this.lastUpdateTimestamp)\n })\n }\n\n get query () {\n return `updates-for[identifier=\"${this.identifier}\"]`\n }\n\n get identifier () {\n return this.getAttribute('identifier')\n }\n\n get debounce () {\n return this.hasAttribute('debounce')\n ? parseInt(this.getAttribute('debounce'))\n : 20\n }\n}\n\nclass Block {\n constructor (element) {\n this.element = element\n }\n\n async process (data, html, index, startTimestamp) {\n const blockIndex = index[this.url]\n const template = document.createElement('template')\n this.element.setAttribute('updating', 'updating')\n\n template.innerHTML = String(html[this.url]).trim()\n\n await this.resolveTurboFrames(template.content)\n\n const fragments = template.content.querySelectorAll(this.query)\n\n if (fragments.length <= blockIndex) {\n console.warn(\n `Update aborted due to insufficient number of elements. The offending url is ${this.url}.`\n )\n return\n }\n\n const operation = {\n element: this.element,\n html: fragments[blockIndex],\n permanentAttributeName: 'data-ignore-updates'\n }\n\n dispatch(this.element, 'cable-ready:before-update', operation)\n Log.morphStart(startTimestamp, this.element)\n\n morphdom(this.element, fragments[blockIndex], {\n childrenOnly: true,\n onBeforeElUpdated: shouldMorph(operation),\n onElUpdated: _ => {\n this.element.removeAttribute('updating')\n dispatch(this.element, 'cable-ready:after-update', operation)\n assignFocus(operation.focusSelector)\n }\n })\n Log.morphEnd(startTimestamp, this.element)\n }\n\n async resolveTurboFrames (documentFragment) {\n const reloadingTurboFrames = [\n ...documentFragment.querySelectorAll(\n 'turbo-frame[src]:not([loading=\"lazy\"])'\n )\n ]\n\n return Promise.all(\n reloadingTurboFrames.map(frame => {\n return new Promise(async resolve => {\n const frameResponse = await graciouslyFetch(\n frame.getAttribute('src'),\n {\n 'Turbo-Frame': frame.id,\n 'X-Cable-Ready': 'update'\n }\n )\n\n const frameTemplate = document.createElement('template')\n frameTemplate.innerHTML = await frameResponse.text()\n\n // recurse here to get all nested eager loaded frames\n await this.resolveTurboFrames(frameTemplate.content)\n\n const selector = `turbo-frame#${frame.id}`\n const frameContent = frameTemplate.content.querySelector(selector)\n const content = frameContent ? frameContent.innerHTML.trim() : ''\n\n docFragment.querySelector(selector).innerHTML = content\n\n resolve()\n })\n })\n )\n }\n\n shouldUpdate (data) {\n // if everything that could prevent an update is false, update this block\n return !this.ignoresInnerUpdates && this.hasChangesSelectedForUpdate(data)\n }\n\n hasChangesSelectedForUpdate (data) {\n // if there's an only attribute, only update if at least one of the attributes changed is in the allow list\n const only = this.element.getAttribute('only')\n\n return !(\n only &&\n data.changed &&\n !only.split(' ').some(attribute => data.changed.includes(attribute))\n )\n }\n\n get ignoresInnerUpdates () {\n // don't update during a Reflex or Turbolinks redraw\n return (\n this.element.hasAttribute('ignore-inner-updates') &&\n this.element.hasAttribute('performing-inner-update')\n )\n }\n\n get url () {\n return this.element.hasAttribute('url')\n ? this.element.getAttribute('url')\n : location.href\n }\n\n get identifier () {\n return this.element.identifier\n }\n\n get query () {\n return this.element.query\n }\n}\n","export const registerInnerUpdates = () => {\n document.addEventListener('stimulus-reflex:before', event => {\n recursiveMarkUpdatesForElements(event.detail.element)\n })\n\n document.addEventListener('stimulus-reflex:after', event => {\n setTimeout(() => {\n recursiveUnmarkUpdatesForElements(event.detail.element)\n })\n })\n\n document.addEventListener('turbo:submit-start', event => {\n recursiveMarkUpdatesForElements(event.target)\n })\n\n document.addEventListener('turbo:submit-end', event => {\n setTimeout(() => {\n recursiveUnmarkUpdatesForElements(event.target)\n })\n })\n\n document.addEventListener('turbo-boost:command:start', event => {\n recursiveMarkUpdatesForElements(event.target)\n })\n\n document.addEventListener('turbo-boost:command:finish', event => {\n setTimeout(() => {\n recursiveUnmarkUpdatesForElements(event.target)\n })\n })\n\n document.addEventListener('turbo-boost:command:error', event => {\n setTimeout(() => {\n recursiveUnmarkUpdatesForElements(event.target)\n })\n })\n}\n\nconst recursiveMarkUpdatesForElements = leaf => {\n const closestUpdatesFor =\n leaf && leaf.parentElement && leaf.parentElement.closest('updates-for')\n if (closestUpdatesFor) {\n closestUpdatesFor.setAttribute('performing-inner-update', '')\n recursiveMarkUpdatesForElements(closestUpdatesFor)\n }\n}\n\nconst recursiveUnmarkUpdatesForElements = leaf => {\n const closestUpdatesFor =\n leaf && leaf.parentElement && leaf.parentElement.closest('updates-for')\n if (closestUpdatesFor) {\n closestUpdatesFor.removeAttribute('performing-inner-update')\n recursiveUnmarkUpdatesForElements(closestUpdatesFor)\n }\n}\n","import StreamFromElement from './stream_from_element'\nimport UpdatesForElement from './updates_for_element'\n\nimport { registerInnerUpdates } from '../updatable/inner_updates_compat'\n\nexport const defineElements = () => {\n registerInnerUpdates()\n\n StreamFromElement.define()\n UpdatesForElement.define()\n}\n","import morphdom from 'morphdom'\n\nimport packageInfo from '../package.json'\nimport { perform, performAsync } from './cable_ready'\nimport { defineElements } from './elements'\nimport { shouldMorphCallbacks, didMorphCallbacks } from './morph_callbacks'\n\nimport * as MorphCallbacks from './morph_callbacks'\nimport * as Utils from './utils'\n\nimport OperationStore, { addOperation, addOperations } from './operation_store'\nimport StreamFromElement from './elements/stream_from_element'\nimport UpdatesForElement from './elements/updates_for_element'\nimport SubscribingElement from './elements/subscribing_element'\nimport CableConsumer from './cable_consumer'\nimport Debug from './debug'\n\nconst initialize = (initializeOptions = {}) => {\n const { consumer, onMissingElement, debug } = initializeOptions\n\n Debug.set(!!debug)\n\n if (consumer) {\n CableConsumer.setConsumer(consumer)\n } else {\n console.error(\n 'CableReady requires a reference to your Action Cable `consumer` for its helpers to function.\\nEnsure that you have imported the `CableReady` package as well as `consumer` from your `channels` folder, then call `CableReady.initialize({ consumer })`.'\n )\n }\n\n if (onMissingElement) {\n MissingElement.set(onMissingElement)\n }\n\n defineElements()\n}\n\nexport {\n Utils,\n MorphCallbacks,\n StreamFromElement,\n UpdatesForElement,\n SubscribingElement\n}\n\nconst global = {\n perform,\n performAsync,\n shouldMorphCallbacks,\n didMorphCallbacks,\n initialize,\n addOperation,\n addOperations,\n version: packageInfo.version,\n cable: CableConsumer,\n get DOMOperations () {\n console.warn(\n 'DEPRECATED: Please use `CableReady.operations` instead of `CableReady.DOMOperations`'\n )\n return OperationStore.all\n },\n get operations () {\n return OperationStore.all\n },\n get consumer () {\n return CableConsumer.consumer\n }\n}\n\nwindow.CableReady = global\n\nexport default global\n"],"names":["inputTags","INPUT","TEXTAREA","SELECT","mutableTags","OPTION","textInputTypes","color","date","datetime","email","month","number","password","range","search","tel","text","textarea","time","url","week","activeElement","ActiveElement","element","set","isTextInput","tagName","type","assignFocus","selector","focusElement","nodeType","Node","ELEMENT_NODE","document","querySelector","focus","dispatch","name","detail","event","CustomEvent","bubbles","cancelable","dispatchEvent","window","jQuery","trigger","xpathToElement","xpath","evaluate","XPathResult","FIRST_ORDERED_NODE_TYPE","singleNodeValue","xpathToElementArray","reverse","snapshotList","ORDERED_NODE_SNAPSHOT_TYPE","snapshots","i","snapshotLength","push","snapshotItem","getClassNames","names","Array","from","flat","processElements","operation","callback","selectAll","forEach","kebabize","result","word","index","toLowerCase","str","words","reduce","match","operate","cancel","delay","setTimeout","before","target","after","debounce","fn","timer","args","clearTimeout","apply","this","handleErrors","response","ok","Error","statusText","safeScalar","val","undefined","includes","console","warn","safeString","String","safeArray","arr","isArray","safeObject","obj","Object","safeStringOrArray","elem","async","graciouslyFetch","additionalHeaders","fetch","headers","e","error","fragment","XMLSerializer","serializeToString","shouldMorph","fromEl","toEl","shouldMorphCallbacks","map","didMorph","el","didMorphCallbacks","verifyNotMutable","isEqualNode","verifyNotContentEditable","isContentEditable","verifyNotPermanent","permanentAttributeName","permanent","closest","ignore","value","attributes","attribute","setAttribute","Operations","append","html","focusSelector","insertAdjacentHTML","graft","parent","parentElement","appendChild","innerHtml","innerHTML","insertAdjacentHtml","position","insertAdjacentText","outerHtml","idx","children","indexOf","outerHTML","documentElement","prepend","remove","replace","textContent","addCssClass","classList","add","removeAttribute","removeCssClass","length","setDatasetProperty","dataset","setProperty","setStyle","style","setStyles","styles","entries","setValue","setMeta","content","meta","head","createElement","setTitle","title","clearStorage","sessionStorage","localStorage","clear","go","delta","history","pushState","state","redirectTo","action","turbo","Turbo","visit","Turbolinks","location","href","reload","removeStorageItem","key","removeItem","replaceState","scrollIntoView","setCookie","cookie","setFocus","setStorageItem","setItem","consoleLog","message","level","log","consoleTable","data","columns","table","notification","options","Notification","requestPermission","then","permission","morph","template","trim","childrenOnly","morphdom","onBeforeElUpdated","onElUpdated","operations","newOperations","OperationStore","all","missingElement","MissingElement$1","behavior","perform","onMissingElement","MissingElement","batches","batch","querySelectorAll","cableReadyOperation","warning","SubscribingElement","HTMLElement","disconnectedCallback","channel","unsubscribe","createSubscription","consumer","receivedCallback","subscriptions","create","identifier","received","preview","hasAttribute","getAttribute","BACKOFF","getConsumerWithRetry","retry","ms","Promise","resolve","CableConsumer","setConsumer","StreamFromElement","static","customElements","get","define","getConsumer","performOperations","bind","cableReady","debugging","Debug","enabled","disabled","debug","Log","blocks","elements","b","identifiers","timestamp","reason","duration","Date","urls","UpdatesForElement","constructor","super","attachShadow","mode","update","lastUpdateTimestamp","query","Block","filter","block","shouldUpdate","uniqueUrls","Set","hasOwnProperty","process","parseInt","startTimestamp","blockIndex","resolveTurboFrames","fragments","_","documentFragment","reloadingTurboFrames","frame","frameResponse","id","frameTemplate","frameContent","docFragment","ignoresInnerUpdates","hasChangesSelectedForUpdate","only","changed","split","some","recursiveMarkUpdatesForElements","leaf","closestUpdatesFor","recursiveUnmarkUpdatesForElements","defineElements","addEventListener","global","performAsync","reject","err","initialize","initializeOptions","addOperation","addOperations","version","packageInfo","cable","DOMOperations","CableReady"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
})(this, (function(exports, morphdom) {
|
|
5
5
|
"use strict";
|
|
6
6
|
var name = "cable_ready";
|
|
7
|
-
var version = "5.0.
|
|
7
|
+
var version = "5.0.1";
|
|
8
8
|
var description = "CableReady helps you create great real-time user experiences by making it simple to trigger client-side DOM changes from server-side Ruby.";
|
|
9
9
|
var keywords = [ "ruby", "rails", "websockets", "actioncable", "cable", "ssr", "stimulus_reflex", "client-side", "dom" ];
|
|
10
10
|
var homepage = "https://cableready.stimulusreflex.com";
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
rollup: "^3.19.1",
|
|
45
45
|
sinon: "^15.0.2",
|
|
46
46
|
vite: "^4.1.4",
|
|
47
|
-
vitepress: "^1.0.0-
|
|
47
|
+
vitepress: "^1.0.0-beta.1",
|
|
48
48
|
"vitepress-plugin-search": "^1.0.4-alpha.19"
|
|
49
49
|
};
|
|
50
50
|
var packageInfo = {
|
|
@@ -248,8 +248,28 @@
|
|
|
248
248
|
console.error(`Could not fetch ${url}`);
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
|
+
class BoundedQueue {
|
|
252
|
+
constructor(maxSize) {
|
|
253
|
+
this.maxSize = maxSize;
|
|
254
|
+
this.queue = [];
|
|
255
|
+
}
|
|
256
|
+
push(item) {
|
|
257
|
+
if (this.isFull()) {
|
|
258
|
+
// Remove the oldest item to make space for the new one
|
|
259
|
+
this.shift();
|
|
260
|
+
}
|
|
261
|
+
this.queue.push(item);
|
|
262
|
+
}
|
|
263
|
+
shift() {
|
|
264
|
+
return this.queue.shift();
|
|
265
|
+
}
|
|
266
|
+
isFull() {
|
|
267
|
+
return this.queue.length === this.maxSize;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
251
270
|
var utils = Object.freeze({
|
|
252
271
|
__proto__: null,
|
|
272
|
+
BoundedQueue: BoundedQueue,
|
|
253
273
|
after: after,
|
|
254
274
|
assignFocus: assignFocus,
|
|
255
275
|
before: before,
|
|
@@ -912,38 +932,48 @@
|
|
|
912
932
|
};
|
|
913
933
|
const request = (data, blocks) => {
|
|
914
934
|
if (Debug.disabled) return;
|
|
915
|
-
|
|
935
|
+
const message = `↑ Updatable request affecting ${blocks.length} element(s): `;
|
|
936
|
+
console.log(message, {
|
|
916
937
|
elements: blocks.map((b => b.element)),
|
|
917
938
|
identifiers: blocks.map((b => b.element.getAttribute("identifier"))),
|
|
918
939
|
data: data
|
|
919
940
|
});
|
|
941
|
+
return message;
|
|
920
942
|
};
|
|
921
943
|
const cancel = (timestamp, reason) => {
|
|
922
944
|
if (Debug.disabled) return;
|
|
923
945
|
const duration = new Date - timestamp;
|
|
924
|
-
|
|
946
|
+
const message = `❌ Updatable request canceled after ${duration}ms: ${reason}`;
|
|
947
|
+
console.log(message);
|
|
948
|
+
return message;
|
|
925
949
|
};
|
|
926
950
|
const response = (timestamp, element, urls) => {
|
|
927
951
|
if (Debug.disabled) return;
|
|
928
952
|
const duration = new Date - timestamp;
|
|
929
|
-
|
|
953
|
+
const message = `↓ Updatable response: All URLs fetched in ${duration}ms`;
|
|
954
|
+
console.log(message, {
|
|
930
955
|
element: element,
|
|
931
956
|
urls: urls
|
|
932
957
|
});
|
|
958
|
+
return message;
|
|
933
959
|
};
|
|
934
960
|
const morphStart = (timestamp, element) => {
|
|
935
961
|
if (Debug.disabled) return;
|
|
936
962
|
const duration = new Date - timestamp;
|
|
937
|
-
|
|
963
|
+
const message = `↻ Updatable morph: starting after ${duration}ms`;
|
|
964
|
+
console.log(message, {
|
|
938
965
|
element: element
|
|
939
966
|
});
|
|
967
|
+
return message;
|
|
940
968
|
};
|
|
941
969
|
const morphEnd = (timestamp, element) => {
|
|
942
970
|
if (Debug.disabled) return;
|
|
943
971
|
const duration = new Date - timestamp;
|
|
944
|
-
|
|
972
|
+
const message = `↺ Updatable morph: completed after ${duration}ms`;
|
|
973
|
+
console.log(message, {
|
|
945
974
|
element: element
|
|
946
975
|
});
|
|
976
|
+
return message;
|
|
947
977
|
};
|
|
948
978
|
var Log = {
|
|
949
979
|
request: request,
|
|
@@ -963,6 +993,8 @@
|
|
|
963
993
|
mode: "open"
|
|
964
994
|
});
|
|
965
995
|
shadowRoot.innerHTML = template;
|
|
996
|
+
this.triggerElementLog = new BoundedQueue(10);
|
|
997
|
+
this.targetElementLog = new BoundedQueue(10);
|
|
966
998
|
}
|
|
967
999
|
async connectedCallback() {
|
|
968
1000
|
if (this.preview) return;
|
|
@@ -977,14 +1009,14 @@
|
|
|
977
1009
|
async update(data) {
|
|
978
1010
|
this.lastUpdateTimestamp = new Date;
|
|
979
1011
|
const blocks = Array.from(document.querySelectorAll(this.query), (element => new Block(element))).filter((block => block.shouldUpdate(data)));
|
|
980
|
-
Log.request(data, blocks);
|
|
1012
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.request(data, blocks)}`);
|
|
981
1013
|
if (blocks.length === 0) {
|
|
982
|
-
Log.cancel(this.lastUpdateTimestamp, "All elements filtered out");
|
|
1014
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.cancel(this.lastUpdateTimestamp, "All elements filtered out")}`);
|
|
983
1015
|
return;
|
|
984
1016
|
}
|
|
985
1017
|
// first <cable-ready-updates-for> element in the DOM *at any given moment* updates all of the others
|
|
986
1018
|
if (blocks[0].element !== this) {
|
|
987
|
-
Log.cancel(this.lastUpdateTimestamp, "Update already requested");
|
|
1019
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.cancel(this.lastUpdateTimestamp, "Update already requested")}`);
|
|
988
1020
|
return;
|
|
989
1021
|
}
|
|
990
1022
|
// hold a reference to the active element so that it can be restored after the morph
|
|
@@ -1000,7 +1032,7 @@
|
|
|
1000
1032
|
this.html[url] = await response.text();
|
|
1001
1033
|
}
|
|
1002
1034
|
})));
|
|
1003
|
-
Log.response(this.lastUpdateTimestamp, this, uniqueUrls);
|
|
1035
|
+
this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.response(this.lastUpdateTimestamp, this, uniqueUrls)}`);
|
|
1004
1036
|
// track current block index for each URL; referred to as fragments
|
|
1005
1037
|
this.index = {};
|
|
1006
1038
|
blocks.forEach((block => {
|
|
@@ -1023,15 +1055,15 @@
|
|
|
1023
1055
|
constructor(element) {
|
|
1024
1056
|
this.element = element;
|
|
1025
1057
|
}
|
|
1026
|
-
async process(data, html,
|
|
1027
|
-
const blockIndex =
|
|
1058
|
+
async process(data, html, fragmentsIndex, startTimestamp) {
|
|
1059
|
+
const blockIndex = fragmentsIndex[this.url];
|
|
1028
1060
|
const template = document.createElement("template");
|
|
1029
1061
|
this.element.setAttribute("updating", "updating");
|
|
1030
1062
|
template.innerHTML = String(html[this.url]).trim();
|
|
1031
1063
|
await this.resolveTurboFrames(template.content);
|
|
1032
1064
|
const fragments = template.content.querySelectorAll(this.query);
|
|
1033
1065
|
if (fragments.length <= blockIndex) {
|
|
1034
|
-
console.warn(`Update aborted due to insufficient number of elements. The offending url is ${this.url}
|
|
1066
|
+
console.warn(`Update aborted due to insufficient number of elements. The offending url is ${this.url}, the offending element is:`, this.element);
|
|
1035
1067
|
return;
|
|
1036
1068
|
}
|
|
1037
1069
|
const operation = {
|
|
@@ -1040,7 +1072,7 @@
|
|
|
1040
1072
|
permanentAttributeName: "data-ignore-updates"
|
|
1041
1073
|
};
|
|
1042
1074
|
dispatch(this.element, "cable-ready:before-update", operation);
|
|
1043
|
-
Log.morphStart(startTimestamp, this.element);
|
|
1075
|
+
this.element.targetElementLog.push(`${(new Date).toLocaleString()}: ${Log.morphStart(startTimestamp, this.element)}`);
|
|
1044
1076
|
morphdom(this.element, fragments[blockIndex], {
|
|
1045
1077
|
childrenOnly: true,
|
|
1046
1078
|
onBeforeElUpdated: shouldMorph(operation),
|
|
@@ -1050,7 +1082,7 @@
|
|
|
1050
1082
|
assignFocus(operation.focusSelector);
|
|
1051
1083
|
}
|
|
1052
1084
|
});
|
|
1053
|
-
Log.morphEnd(startTimestamp, this.element);
|
|
1085
|
+
this.element.targetElementLog.push(`${(new Date).toLocaleString()}: ${Log.morphEnd(startTimestamp, this.element)}`);
|
|
1054
1086
|
}
|
|
1055
1087
|
async resolveTurboFrames(documentFragment) {
|
|
1056
1088
|
const reloadingTurboFrames = [ ...documentFragment.querySelectorAll('turbo-frame[src]:not([loading="lazy"])') ];
|