cable_ready-element 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1759 @@
1
+ var DOCUMENT_FRAGMENT_NODE = 11;
2
+
3
+ function morphAttrs(fromNode, toNode) {
4
+ var toNodeAttrs = toNode.attributes;
5
+ var attr;
6
+ var attrName;
7
+ var attrNamespaceURI;
8
+ var attrValue;
9
+ var fromValue;
10
+ if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {
11
+ return;
12
+ }
13
+ for (var i = toNodeAttrs.length - 1; i >= 0; i--) {
14
+ attr = toNodeAttrs[i];
15
+ attrName = attr.name;
16
+ attrNamespaceURI = attr.namespaceURI;
17
+ attrValue = attr.value;
18
+ if (attrNamespaceURI) {
19
+ attrName = attr.localName || attrName;
20
+ fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);
21
+ if (fromValue !== attrValue) {
22
+ if (attr.prefix === "xmlns") {
23
+ attrName = attr.name;
24
+ }
25
+ fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
26
+ }
27
+ } else {
28
+ fromValue = fromNode.getAttribute(attrName);
29
+ if (fromValue !== attrValue) {
30
+ fromNode.setAttribute(attrName, attrValue);
31
+ }
32
+ }
33
+ }
34
+ var fromNodeAttrs = fromNode.attributes;
35
+ for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {
36
+ attr = fromNodeAttrs[d];
37
+ attrName = attr.name;
38
+ attrNamespaceURI = attr.namespaceURI;
39
+ if (attrNamespaceURI) {
40
+ attrName = attr.localName || attrName;
41
+ if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {
42
+ fromNode.removeAttributeNS(attrNamespaceURI, attrName);
43
+ }
44
+ } else {
45
+ if (!toNode.hasAttribute(attrName)) {
46
+ fromNode.removeAttribute(attrName);
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ var range;
53
+
54
+ var NS_XHTML = "http://www.w3.org/1999/xhtml";
55
+
56
+ var doc = typeof document === "undefined" ? undefined : document;
57
+
58
+ var HAS_TEMPLATE_SUPPORT = !!doc && "content" in doc.createElement("template");
59
+
60
+ var HAS_RANGE_SUPPORT = !!doc && doc.createRange && "createContextualFragment" in doc.createRange();
61
+
62
+ function createFragmentFromTemplate(str) {
63
+ var template = doc.createElement("template");
64
+ template.innerHTML = str;
65
+ return template.content.childNodes[0];
66
+ }
67
+
68
+ function createFragmentFromRange(str) {
69
+ if (!range) {
70
+ range = doc.createRange();
71
+ range.selectNode(doc.body);
72
+ }
73
+ var fragment = range.createContextualFragment(str);
74
+ return fragment.childNodes[0];
75
+ }
76
+
77
+ function createFragmentFromWrap(str) {
78
+ var fragment = doc.createElement("body");
79
+ fragment.innerHTML = str;
80
+ return fragment.childNodes[0];
81
+ }
82
+
83
+ function toElement(str) {
84
+ str = str.trim();
85
+ if (HAS_TEMPLATE_SUPPORT) {
86
+ return createFragmentFromTemplate(str);
87
+ } else if (HAS_RANGE_SUPPORT) {
88
+ return createFragmentFromRange(str);
89
+ }
90
+ return createFragmentFromWrap(str);
91
+ }
92
+
93
+ function compareNodeNames(fromEl, toEl) {
94
+ var fromNodeName = fromEl.nodeName;
95
+ var toNodeName = toEl.nodeName;
96
+ var fromCodeStart, toCodeStart;
97
+ if (fromNodeName === toNodeName) {
98
+ return true;
99
+ }
100
+ fromCodeStart = fromNodeName.charCodeAt(0);
101
+ toCodeStart = toNodeName.charCodeAt(0);
102
+ if (fromCodeStart <= 90 && toCodeStart >= 97) {
103
+ return fromNodeName === toNodeName.toUpperCase();
104
+ } else if (toCodeStart <= 90 && fromCodeStart >= 97) {
105
+ return toNodeName === fromNodeName.toUpperCase();
106
+ } else {
107
+ return false;
108
+ }
109
+ }
110
+
111
+ function createElementNS(name, namespaceURI) {
112
+ return !namespaceURI || namespaceURI === NS_XHTML ? doc.createElement(name) : doc.createElementNS(namespaceURI, name);
113
+ }
114
+
115
+ function moveChildren(fromEl, toEl) {
116
+ var curChild = fromEl.firstChild;
117
+ while (curChild) {
118
+ var nextChild = curChild.nextSibling;
119
+ toEl.appendChild(curChild);
120
+ curChild = nextChild;
121
+ }
122
+ return toEl;
123
+ }
124
+
125
+ function syncBooleanAttrProp(fromEl, toEl, name) {
126
+ if (fromEl[name] !== toEl[name]) {
127
+ fromEl[name] = toEl[name];
128
+ if (fromEl[name]) {
129
+ fromEl.setAttribute(name, "");
130
+ } else {
131
+ fromEl.removeAttribute(name);
132
+ }
133
+ }
134
+ }
135
+
136
+ var specialElHandlers = {
137
+ OPTION: function(fromEl, toEl) {
138
+ var parentNode = fromEl.parentNode;
139
+ if (parentNode) {
140
+ var parentName = parentNode.nodeName.toUpperCase();
141
+ if (parentName === "OPTGROUP") {
142
+ parentNode = parentNode.parentNode;
143
+ parentName = parentNode && parentNode.nodeName.toUpperCase();
144
+ }
145
+ if (parentName === "SELECT" && !parentNode.hasAttribute("multiple")) {
146
+ if (fromEl.hasAttribute("selected") && !toEl.selected) {
147
+ fromEl.setAttribute("selected", "selected");
148
+ fromEl.removeAttribute("selected");
149
+ }
150
+ parentNode.selectedIndex = -1;
151
+ }
152
+ }
153
+ syncBooleanAttrProp(fromEl, toEl, "selected");
154
+ },
155
+ INPUT: function(fromEl, toEl) {
156
+ syncBooleanAttrProp(fromEl, toEl, "checked");
157
+ syncBooleanAttrProp(fromEl, toEl, "disabled");
158
+ if (fromEl.value !== toEl.value) {
159
+ fromEl.value = toEl.value;
160
+ }
161
+ if (!toEl.hasAttribute("value")) {
162
+ fromEl.removeAttribute("value");
163
+ }
164
+ },
165
+ TEXTAREA: function(fromEl, toEl) {
166
+ var newValue = toEl.value;
167
+ if (fromEl.value !== newValue) {
168
+ fromEl.value = newValue;
169
+ }
170
+ var firstChild = fromEl.firstChild;
171
+ if (firstChild) {
172
+ var oldValue = firstChild.nodeValue;
173
+ if (oldValue == newValue || !newValue && oldValue == fromEl.placeholder) {
174
+ return;
175
+ }
176
+ firstChild.nodeValue = newValue;
177
+ }
178
+ },
179
+ SELECT: function(fromEl, toEl) {
180
+ if (!toEl.hasAttribute("multiple")) {
181
+ var selectedIndex = -1;
182
+ var i = 0;
183
+ var curChild = fromEl.firstChild;
184
+ var optgroup;
185
+ var nodeName;
186
+ while (curChild) {
187
+ nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
188
+ if (nodeName === "OPTGROUP") {
189
+ optgroup = curChild;
190
+ curChild = optgroup.firstChild;
191
+ } else {
192
+ if (nodeName === "OPTION") {
193
+ if (curChild.hasAttribute("selected")) {
194
+ selectedIndex = i;
195
+ break;
196
+ }
197
+ i++;
198
+ }
199
+ curChild = curChild.nextSibling;
200
+ if (!curChild && optgroup) {
201
+ curChild = optgroup.nextSibling;
202
+ optgroup = null;
203
+ }
204
+ }
205
+ }
206
+ fromEl.selectedIndex = selectedIndex;
207
+ }
208
+ }
209
+ };
210
+
211
+ var ELEMENT_NODE = 1;
212
+
213
+ var DOCUMENT_FRAGMENT_NODE$1 = 11;
214
+
215
+ var TEXT_NODE = 3;
216
+
217
+ var COMMENT_NODE = 8;
218
+
219
+ function noop() {}
220
+
221
+ function defaultGetNodeKey(node) {
222
+ if (node) {
223
+ return node.getAttribute && node.getAttribute("id") || node.id;
224
+ }
225
+ }
226
+
227
+ function morphdomFactory(morphAttrs) {
228
+ return function morphdom(fromNode, toNode, options) {
229
+ if (!options) {
230
+ options = {};
231
+ }
232
+ if (typeof toNode === "string") {
233
+ if (fromNode.nodeName === "#document" || fromNode.nodeName === "HTML" || fromNode.nodeName === "BODY") {
234
+ var toNodeHtml = toNode;
235
+ toNode = doc.createElement("html");
236
+ toNode.innerHTML = toNodeHtml;
237
+ } else {
238
+ toNode = toElement(toNode);
239
+ }
240
+ }
241
+ var getNodeKey = options.getNodeKey || defaultGetNodeKey;
242
+ var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
243
+ var onNodeAdded = options.onNodeAdded || noop;
244
+ var onBeforeElUpdated = options.onBeforeElUpdated || noop;
245
+ var onElUpdated = options.onElUpdated || noop;
246
+ var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
247
+ var onNodeDiscarded = options.onNodeDiscarded || noop;
248
+ var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
249
+ var childrenOnly = options.childrenOnly === true;
250
+ var fromNodesLookup = Object.create(null);
251
+ var keyedRemovalList = [];
252
+ function addKeyedRemoval(key) {
253
+ keyedRemovalList.push(key);
254
+ }
255
+ function walkDiscardedChildNodes(node, skipKeyedNodes) {
256
+ if (node.nodeType === ELEMENT_NODE) {
257
+ var curChild = node.firstChild;
258
+ while (curChild) {
259
+ var key = undefined;
260
+ if (skipKeyedNodes && (key = getNodeKey(curChild))) {
261
+ addKeyedRemoval(key);
262
+ } else {
263
+ onNodeDiscarded(curChild);
264
+ if (curChild.firstChild) {
265
+ walkDiscardedChildNodes(curChild, skipKeyedNodes);
266
+ }
267
+ }
268
+ curChild = curChild.nextSibling;
269
+ }
270
+ }
271
+ }
272
+ function removeNode(node, parentNode, skipKeyedNodes) {
273
+ if (onBeforeNodeDiscarded(node) === false) {
274
+ return;
275
+ }
276
+ if (parentNode) {
277
+ parentNode.removeChild(node);
278
+ }
279
+ onNodeDiscarded(node);
280
+ walkDiscardedChildNodes(node, skipKeyedNodes);
281
+ }
282
+ function indexTree(node) {
283
+ if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
284
+ var curChild = node.firstChild;
285
+ while (curChild) {
286
+ var key = getNodeKey(curChild);
287
+ if (key) {
288
+ fromNodesLookup[key] = curChild;
289
+ }
290
+ indexTree(curChild);
291
+ curChild = curChild.nextSibling;
292
+ }
293
+ }
294
+ }
295
+ indexTree(fromNode);
296
+ function handleNodeAdded(el) {
297
+ onNodeAdded(el);
298
+ var curChild = el.firstChild;
299
+ while (curChild) {
300
+ var nextSibling = curChild.nextSibling;
301
+ var key = getNodeKey(curChild);
302
+ if (key) {
303
+ var unmatchedFromEl = fromNodesLookup[key];
304
+ if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
305
+ curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
306
+ morphEl(unmatchedFromEl, curChild);
307
+ } else {
308
+ handleNodeAdded(curChild);
309
+ }
310
+ } else {
311
+ handleNodeAdded(curChild);
312
+ }
313
+ curChild = nextSibling;
314
+ }
315
+ }
316
+ function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
317
+ while (curFromNodeChild) {
318
+ var fromNextSibling = curFromNodeChild.nextSibling;
319
+ if (curFromNodeKey = getNodeKey(curFromNodeChild)) {
320
+ addKeyedRemoval(curFromNodeKey);
321
+ } else {
322
+ removeNode(curFromNodeChild, fromEl, true);
323
+ }
324
+ curFromNodeChild = fromNextSibling;
325
+ }
326
+ }
327
+ function morphEl(fromEl, toEl, childrenOnly) {
328
+ var toElKey = getNodeKey(toEl);
329
+ if (toElKey) {
330
+ delete fromNodesLookup[toElKey];
331
+ }
332
+ if (!childrenOnly) {
333
+ if (onBeforeElUpdated(fromEl, toEl) === false) {
334
+ return;
335
+ }
336
+ morphAttrs(fromEl, toEl);
337
+ onElUpdated(fromEl);
338
+ if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
339
+ return;
340
+ }
341
+ }
342
+ if (fromEl.nodeName !== "TEXTAREA") {
343
+ morphChildren(fromEl, toEl);
344
+ } else {
345
+ specialElHandlers.TEXTAREA(fromEl, toEl);
346
+ }
347
+ }
348
+ function morphChildren(fromEl, toEl) {
349
+ var curToNodeChild = toEl.firstChild;
350
+ var curFromNodeChild = fromEl.firstChild;
351
+ var curToNodeKey;
352
+ var curFromNodeKey;
353
+ var fromNextSibling;
354
+ var toNextSibling;
355
+ var matchingFromEl;
356
+ outer: while (curToNodeChild) {
357
+ toNextSibling = curToNodeChild.nextSibling;
358
+ curToNodeKey = getNodeKey(curToNodeChild);
359
+ while (curFromNodeChild) {
360
+ fromNextSibling = curFromNodeChild.nextSibling;
361
+ if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
362
+ curToNodeChild = toNextSibling;
363
+ curFromNodeChild = fromNextSibling;
364
+ continue outer;
365
+ }
366
+ curFromNodeKey = getNodeKey(curFromNodeChild);
367
+ var curFromNodeType = curFromNodeChild.nodeType;
368
+ var isCompatible = undefined;
369
+ if (curFromNodeType === curToNodeChild.nodeType) {
370
+ if (curFromNodeType === ELEMENT_NODE) {
371
+ if (curToNodeKey) {
372
+ if (curToNodeKey !== curFromNodeKey) {
373
+ if (matchingFromEl = fromNodesLookup[curToNodeKey]) {
374
+ if (fromNextSibling === matchingFromEl) {
375
+ isCompatible = false;
376
+ } else {
377
+ fromEl.insertBefore(matchingFromEl, curFromNodeChild);
378
+ if (curFromNodeKey) {
379
+ addKeyedRemoval(curFromNodeKey);
380
+ } else {
381
+ removeNode(curFromNodeChild, fromEl, true);
382
+ }
383
+ curFromNodeChild = matchingFromEl;
384
+ }
385
+ } else {
386
+ isCompatible = false;
387
+ }
388
+ }
389
+ } else if (curFromNodeKey) {
390
+ isCompatible = false;
391
+ }
392
+ isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
393
+ if (isCompatible) {
394
+ morphEl(curFromNodeChild, curToNodeChild);
395
+ }
396
+ } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
397
+ isCompatible = true;
398
+ if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
399
+ curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
400
+ }
401
+ }
402
+ }
403
+ if (isCompatible) {
404
+ curToNodeChild = toNextSibling;
405
+ curFromNodeChild = fromNextSibling;
406
+ continue outer;
407
+ }
408
+ if (curFromNodeKey) {
409
+ addKeyedRemoval(curFromNodeKey);
410
+ } else {
411
+ removeNode(curFromNodeChild, fromEl, true);
412
+ }
413
+ curFromNodeChild = fromNextSibling;
414
+ }
415
+ if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
416
+ fromEl.appendChild(matchingFromEl);
417
+ morphEl(matchingFromEl, curToNodeChild);
418
+ } else {
419
+ var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
420
+ if (onBeforeNodeAddedResult !== false) {
421
+ if (onBeforeNodeAddedResult) {
422
+ curToNodeChild = onBeforeNodeAddedResult;
423
+ }
424
+ if (curToNodeChild.actualize) {
425
+ curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
426
+ }
427
+ fromEl.appendChild(curToNodeChild);
428
+ handleNodeAdded(curToNodeChild);
429
+ }
430
+ }
431
+ curToNodeChild = toNextSibling;
432
+ curFromNodeChild = fromNextSibling;
433
+ }
434
+ cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
435
+ var specialElHandler = specialElHandlers[fromEl.nodeName];
436
+ if (specialElHandler) {
437
+ specialElHandler(fromEl, toEl);
438
+ }
439
+ }
440
+ var morphedNode = fromNode;
441
+ var morphedNodeType = morphedNode.nodeType;
442
+ var toNodeType = toNode.nodeType;
443
+ if (!childrenOnly) {
444
+ if (morphedNodeType === ELEMENT_NODE) {
445
+ if (toNodeType === ELEMENT_NODE) {
446
+ if (!compareNodeNames(fromNode, toNode)) {
447
+ onNodeDiscarded(fromNode);
448
+ morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
449
+ }
450
+ } else {
451
+ morphedNode = toNode;
452
+ }
453
+ } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) {
454
+ if (toNodeType === morphedNodeType) {
455
+ if (morphedNode.nodeValue !== toNode.nodeValue) {
456
+ morphedNode.nodeValue = toNode.nodeValue;
457
+ }
458
+ return morphedNode;
459
+ } else {
460
+ morphedNode = toNode;
461
+ }
462
+ }
463
+ }
464
+ if (morphedNode === toNode) {
465
+ onNodeDiscarded(fromNode);
466
+ } else {
467
+ if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
468
+ return;
469
+ }
470
+ morphEl(morphedNode, toNode, childrenOnly);
471
+ if (keyedRemovalList) {
472
+ for (var i = 0, len = keyedRemovalList.length; i < len; i++) {
473
+ var elToRemove = fromNodesLookup[keyedRemovalList[i]];
474
+ if (elToRemove) {
475
+ removeNode(elToRemove, elToRemove.parentNode, false);
476
+ }
477
+ }
478
+ }
479
+ }
480
+ if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
481
+ if (morphedNode.actualize) {
482
+ morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
483
+ }
484
+ fromNode.parentNode.replaceChild(morphedNode, fromNode);
485
+ }
486
+ return morphedNode;
487
+ };
488
+ }
489
+
490
+ var morphdom = morphdomFactory(morphAttrs);
491
+
492
+ var name = "cable_ready";
493
+
494
+ var version = "5.0.1";
495
+
496
+ 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.";
497
+
498
+ var keywords = [ "ruby", "rails", "websockets", "actioncable", "cable", "ssr", "stimulus_reflex", "client-side", "dom" ];
499
+
500
+ var homepage = "https://cableready.stimulusreflex.com";
501
+
502
+ var bugs = "https://github.com/stimulusreflex/cable_ready/issues";
503
+
504
+ var repository = "https://github.com/stimulusreflex/cable_ready";
505
+
506
+ var license = "MIT";
507
+
508
+ var author = "Nathan Hopkins <natehop@gmail.com>";
509
+
510
+ var contributors = [ "Andrew Mason <andrewmcodes@protonmail.com>", "Julian Rubisch <julian@julianrubisch.at>", "Marco Roth <marco.roth@intergga.ch>", "Nathan Hopkins <natehop@gmail.com>" ];
511
+
512
+ var main = "./dist/cable_ready.js";
513
+
514
+ var module = "./dist/cable_ready.js";
515
+
516
+ var browser = "./dist/cable_ready.js";
517
+
518
+ var unpkg = "./dist/cable_ready.umd.js";
519
+
520
+ var umd = "./dist/cable_ready.umd.js";
521
+
522
+ var files = [ "dist/*", "javascript/*" ];
523
+
524
+ var scripts = {
525
+ lint: "yarn run format --check",
526
+ format: "yarn run prettier-standard ./javascript/**/*.js rollup.config.mjs",
527
+ build: "yarn rollup -c",
528
+ watch: "yarn rollup -wc",
529
+ test: "web-test-runner javascript/test/**/*.test.js",
530
+ "docs:dev": "vitepress dev docs",
531
+ "docs:build": "vitepress build docs && cp ./docs/_redirects ./docs/.vitepress/dist",
532
+ "docs:preview": "vitepress preview docs"
533
+ };
534
+
535
+ var dependencies = {
536
+ morphdom: "2.6.1"
537
+ };
538
+
539
+ var devDependencies = {
540
+ "@open-wc/testing": "^3.1.7",
541
+ "@rollup/plugin-json": "^6.0.0",
542
+ "@rollup/plugin-node-resolve": "^15.0.1",
543
+ "@rollup/plugin-terser": "^0.4.0",
544
+ "@web/dev-server-esbuild": "^0.3.3",
545
+ "@web/dev-server-rollup": "^0.3.21",
546
+ "@web/test-runner": "^0.15.1",
547
+ "prettier-standard": "^16.4.1",
548
+ rollup: "^3.19.1",
549
+ sinon: "^15.0.2",
550
+ vite: "^4.1.4",
551
+ vitepress: "^1.0.0-beta.1",
552
+ "vitepress-plugin-search": "^1.0.4-alpha.19"
553
+ };
554
+
555
+ var packageInfo = {
556
+ name: name,
557
+ version: version,
558
+ description: description,
559
+ keywords: keywords,
560
+ homepage: homepage,
561
+ bugs: bugs,
562
+ repository: repository,
563
+ license: license,
564
+ author: author,
565
+ contributors: contributors,
566
+ main: main,
567
+ module: module,
568
+ browser: browser,
569
+ import: "./dist/cable_ready.js",
570
+ unpkg: unpkg,
571
+ umd: umd,
572
+ files: files,
573
+ scripts: scripts,
574
+ dependencies: dependencies,
575
+ devDependencies: devDependencies
576
+ };
577
+
578
+ const inputTags = {
579
+ INPUT: true,
580
+ TEXTAREA: true,
581
+ SELECT: true
582
+ };
583
+
584
+ const mutableTags = {
585
+ INPUT: true,
586
+ TEXTAREA: true,
587
+ OPTION: true
588
+ };
589
+
590
+ const textInputTypes = {
591
+ "datetime-local": true,
592
+ "select-multiple": true,
593
+ "select-one": true,
594
+ color: true,
595
+ date: true,
596
+ datetime: true,
597
+ email: true,
598
+ month: true,
599
+ number: true,
600
+ password: true,
601
+ range: true,
602
+ search: true,
603
+ tel: true,
604
+ text: true,
605
+ textarea: true,
606
+ time: true,
607
+ url: true,
608
+ week: true
609
+ };
610
+
611
+ let activeElement;
612
+
613
+ var ActiveElement = {
614
+ get element() {
615
+ return activeElement;
616
+ },
617
+ set(element) {
618
+ activeElement = element;
619
+ }
620
+ };
621
+
622
+ const isTextInput = element => inputTags[element.tagName] && textInputTypes[element.type];
623
+
624
+ const assignFocus = selector => {
625
+ const element = selector && selector.nodeType === Node.ELEMENT_NODE ? selector : document.querySelector(selector);
626
+ const focusElement = element || ActiveElement.element;
627
+ if (focusElement && focusElement.focus) focusElement.focus();
628
+ };
629
+
630
+ const dispatch = (element, name, detail = {}) => {
631
+ const init = {
632
+ bubbles: true,
633
+ cancelable: true,
634
+ detail: detail
635
+ };
636
+ const event = new CustomEvent(name, init);
637
+ element.dispatchEvent(event);
638
+ if (window.jQuery) window.jQuery(element).trigger(name, detail);
639
+ };
640
+
641
+ const xpathToElement = xpath => document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
642
+
643
+ const xpathToElementArray = (xpath, reverse = false) => {
644
+ const snapshotList = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
645
+ const snapshots = [];
646
+ for (let i = 0; i < snapshotList.snapshotLength; i++) {
647
+ snapshots.push(snapshotList.snapshotItem(i));
648
+ }
649
+ return reverse ? snapshots.reverse() : snapshots;
650
+ };
651
+
652
+ const getClassNames = names => Array.from(names).flat();
653
+
654
+ const processElements = (operation, callback) => {
655
+ Array.from(operation.selectAll ? operation.element : [ operation.element ]).forEach(callback);
656
+ };
657
+
658
+ const kebabize = createCompounder((function(result, word, index) {
659
+ return result + (index ? "-" : "") + word.toLowerCase();
660
+ }));
661
+
662
+ function createCompounder(callback) {
663
+ return function(str) {
664
+ return words(str).reduce(callback, "");
665
+ };
666
+ }
667
+
668
+ const words = str => {
669
+ str = str == null ? "" : str;
670
+ return str.match(/([A-Z]{2,}|[0-9]+|[A-Z]?[a-z]+|[A-Z])/g) || [];
671
+ };
672
+
673
+ const operate = (operation, callback) => {
674
+ if (!operation.cancel) {
675
+ operation.delay ? setTimeout(callback, operation.delay) : callback();
676
+ return true;
677
+ }
678
+ return false;
679
+ };
680
+
681
+ const before = (target, operation) => dispatch(target, `cable-ready:before-${kebabize(operation.operation)}`, operation);
682
+
683
+ const after = (target, operation) => dispatch(target, `cable-ready:after-${kebabize(operation.operation)}`, operation);
684
+
685
+ function debounce(fn, delay = 250) {
686
+ let timer;
687
+ return (...args) => {
688
+ const callback = () => fn.apply(this, args);
689
+ if (timer) clearTimeout(timer);
690
+ timer = setTimeout(callback, delay);
691
+ };
692
+ }
693
+
694
+ function handleErrors(response) {
695
+ if (!response.ok) throw Error(response.statusText);
696
+ return response;
697
+ }
698
+
699
+ function safeScalar(val) {
700
+ if (val !== undefined && ![ "string", "number", "boolean" ].includes(typeof val)) console.warn(`Operation expects a string, number or boolean, but got ${val} (${typeof val})`);
701
+ return val != null ? val : "";
702
+ }
703
+
704
+ function safeString(str) {
705
+ if (str !== undefined && typeof str !== "string") console.warn(`Operation expects a string, but got ${str} (${typeof str})`);
706
+ return str != null ? String(str) : "";
707
+ }
708
+
709
+ function safeArray(arr) {
710
+ if (arr !== undefined && !Array.isArray(arr)) console.warn(`Operation expects an array, but got ${arr} (${typeof arr})`);
711
+ return arr != null ? Array.from(arr) : [];
712
+ }
713
+
714
+ function safeObject(obj) {
715
+ if (obj !== undefined && typeof obj !== "object") console.warn(`Operation expects an object, but got ${obj} (${typeof obj})`);
716
+ return obj != null ? Object(obj) : {};
717
+ }
718
+
719
+ function safeStringOrArray(elem) {
720
+ if (elem !== undefined && !Array.isArray(elem) && typeof elem !== "string") console.warn(`Operation expects an Array or a String, but got ${elem} (${typeof elem})`);
721
+ return elem == null ? "" : Array.isArray(elem) ? Array.from(elem) : String(elem);
722
+ }
723
+
724
+ function fragmentToString(fragment) {
725
+ return (new XMLSerializer).serializeToString(fragment);
726
+ }
727
+
728
+ async function graciouslyFetch(url, additionalHeaders) {
729
+ try {
730
+ const response = await fetch(url, {
731
+ headers: {
732
+ "X-REQUESTED-WITH": "XmlHttpRequest",
733
+ ...additionalHeaders
734
+ }
735
+ });
736
+ if (response == undefined) return;
737
+ handleErrors(response);
738
+ return response;
739
+ } catch (e) {
740
+ console.error(`Could not fetch ${url}`);
741
+ }
742
+ }
743
+
744
+ class BoundedQueue {
745
+ constructor(maxSize) {
746
+ this.maxSize = maxSize;
747
+ this.queue = [];
748
+ }
749
+ push(item) {
750
+ if (this.isFull()) {
751
+ this.shift();
752
+ }
753
+ this.queue.push(item);
754
+ }
755
+ shift() {
756
+ return this.queue.shift();
757
+ }
758
+ isFull() {
759
+ return this.queue.length === this.maxSize;
760
+ }
761
+ }
762
+
763
+ Object.freeze({
764
+ __proto__: null,
765
+ BoundedQueue: BoundedQueue,
766
+ after: after,
767
+ assignFocus: assignFocus,
768
+ before: before,
769
+ debounce: debounce,
770
+ dispatch: dispatch,
771
+ fragmentToString: fragmentToString,
772
+ getClassNames: getClassNames,
773
+ graciouslyFetch: graciouslyFetch,
774
+ handleErrors: handleErrors,
775
+ isTextInput: isTextInput,
776
+ kebabize: kebabize,
777
+ operate: operate,
778
+ processElements: processElements,
779
+ safeArray: safeArray,
780
+ safeObject: safeObject,
781
+ safeScalar: safeScalar,
782
+ safeString: safeString,
783
+ safeStringOrArray: safeStringOrArray,
784
+ xpathToElement: xpathToElement,
785
+ xpathToElementArray: xpathToElementArray
786
+ });
787
+
788
+ const shouldMorph = operation => (fromEl, toEl) => !shouldMorphCallbacks.map((callback => typeof callback === "function" ? callback(operation, fromEl, toEl) : true)).includes(false);
789
+
790
+ const didMorph = operation => el => {
791
+ didMorphCallbacks.forEach((callback => {
792
+ if (typeof callback === "function") callback(operation, el);
793
+ }));
794
+ };
795
+
796
+ const verifyNotMutable = (detail, fromEl, toEl) => {
797
+ if (!mutableTags[fromEl.tagName] && fromEl.isEqualNode(toEl)) return false;
798
+ return true;
799
+ };
800
+
801
+ const verifyNotContentEditable = (detail, fromEl, toEl) => {
802
+ if (fromEl === ActiveElement.element && fromEl.isContentEditable) return false;
803
+ return true;
804
+ };
805
+
806
+ const verifyNotPermanent = (detail, fromEl, toEl) => {
807
+ const {permanentAttributeName: permanentAttributeName} = detail;
808
+ if (!permanentAttributeName) return true;
809
+ const permanent = fromEl.closest(`[${permanentAttributeName}]`);
810
+ if (!permanent && fromEl === ActiveElement.element && isTextInput(fromEl)) {
811
+ const ignore = {
812
+ value: true
813
+ };
814
+ Array.from(toEl.attributes).forEach((attribute => {
815
+ if (!ignore[attribute.name]) fromEl.setAttribute(attribute.name, attribute.value);
816
+ }));
817
+ return false;
818
+ }
819
+ return !permanent;
820
+ };
821
+
822
+ const shouldMorphCallbacks = [ verifyNotMutable, verifyNotPermanent, verifyNotContentEditable ];
823
+
824
+ const didMorphCallbacks = [];
825
+
826
+ Object.freeze({
827
+ __proto__: null,
828
+ didMorph: didMorph,
829
+ didMorphCallbacks: didMorphCallbacks,
830
+ shouldMorph: shouldMorph,
831
+ shouldMorphCallbacks: shouldMorphCallbacks,
832
+ verifyNotContentEditable: verifyNotContentEditable,
833
+ verifyNotMutable: verifyNotMutable,
834
+ verifyNotPermanent: verifyNotPermanent
835
+ });
836
+
837
+ var Operations = {
838
+ append: operation => {
839
+ processElements(operation, (element => {
840
+ before(element, operation);
841
+ operate(operation, (() => {
842
+ const {html: html, focusSelector: focusSelector} = operation;
843
+ element.insertAdjacentHTML("beforeend", safeScalar(html));
844
+ assignFocus(focusSelector);
845
+ }));
846
+ after(element, operation);
847
+ }));
848
+ },
849
+ graft: operation => {
850
+ processElements(operation, (element => {
851
+ before(element, operation);
852
+ operate(operation, (() => {
853
+ const {parent: parent, focusSelector: focusSelector} = operation;
854
+ const parentElement = document.querySelector(parent);
855
+ if (parentElement) {
856
+ parentElement.appendChild(element);
857
+ assignFocus(focusSelector);
858
+ }
859
+ }));
860
+ after(element, operation);
861
+ }));
862
+ },
863
+ innerHtml: operation => {
864
+ processElements(operation, (element => {
865
+ before(element, operation);
866
+ operate(operation, (() => {
867
+ const {html: html, focusSelector: focusSelector} = operation;
868
+ element.innerHTML = safeScalar(html);
869
+ assignFocus(focusSelector);
870
+ }));
871
+ after(element, operation);
872
+ }));
873
+ },
874
+ insertAdjacentHtml: operation => {
875
+ processElements(operation, (element => {
876
+ before(element, operation);
877
+ operate(operation, (() => {
878
+ const {html: html, position: position, focusSelector: focusSelector} = operation;
879
+ element.insertAdjacentHTML(position || "beforeend", safeScalar(html));
880
+ assignFocus(focusSelector);
881
+ }));
882
+ after(element, operation);
883
+ }));
884
+ },
885
+ insertAdjacentText: operation => {
886
+ processElements(operation, (element => {
887
+ before(element, operation);
888
+ operate(operation, (() => {
889
+ const {text: text, position: position, focusSelector: focusSelector} = operation;
890
+ element.insertAdjacentText(position || "beforeend", safeScalar(text));
891
+ assignFocus(focusSelector);
892
+ }));
893
+ after(element, operation);
894
+ }));
895
+ },
896
+ outerHtml: operation => {
897
+ processElements(operation, (element => {
898
+ const parent = element.parentElement;
899
+ const idx = parent && Array.from(parent.children).indexOf(element);
900
+ before(element, operation);
901
+ operate(operation, (() => {
902
+ const {html: html, focusSelector: focusSelector} = operation;
903
+ element.outerHTML = safeScalar(html);
904
+ assignFocus(focusSelector);
905
+ }));
906
+ after(parent ? parent.children[idx] : document.documentElement, operation);
907
+ }));
908
+ },
909
+ prepend: operation => {
910
+ processElements(operation, (element => {
911
+ before(element, operation);
912
+ operate(operation, (() => {
913
+ const {html: html, focusSelector: focusSelector} = operation;
914
+ element.insertAdjacentHTML("afterbegin", safeScalar(html));
915
+ assignFocus(focusSelector);
916
+ }));
917
+ after(element, operation);
918
+ }));
919
+ },
920
+ remove: operation => {
921
+ processElements(operation, (element => {
922
+ before(element, operation);
923
+ operate(operation, (() => {
924
+ const {focusSelector: focusSelector} = operation;
925
+ element.remove();
926
+ assignFocus(focusSelector);
927
+ }));
928
+ after(document, operation);
929
+ }));
930
+ },
931
+ replace: operation => {
932
+ processElements(operation, (element => {
933
+ const parent = element.parentElement;
934
+ const idx = parent && Array.from(parent.children).indexOf(element);
935
+ before(element, operation);
936
+ operate(operation, (() => {
937
+ const {html: html, focusSelector: focusSelector} = operation;
938
+ element.outerHTML = safeScalar(html);
939
+ assignFocus(focusSelector);
940
+ }));
941
+ after(parent ? parent.children[idx] : document.documentElement, operation);
942
+ }));
943
+ },
944
+ textContent: operation => {
945
+ processElements(operation, (element => {
946
+ before(element, operation);
947
+ operate(operation, (() => {
948
+ const {text: text, focusSelector: focusSelector} = operation;
949
+ element.textContent = safeScalar(text);
950
+ assignFocus(focusSelector);
951
+ }));
952
+ after(element, operation);
953
+ }));
954
+ },
955
+ addCssClass: operation => {
956
+ processElements(operation, (element => {
957
+ before(element, operation);
958
+ operate(operation, (() => {
959
+ const {name: name} = operation;
960
+ element.classList.add(...getClassNames([ safeStringOrArray(name) ]));
961
+ }));
962
+ after(element, operation);
963
+ }));
964
+ },
965
+ removeAttribute: operation => {
966
+ processElements(operation, (element => {
967
+ before(element, operation);
968
+ operate(operation, (() => {
969
+ const {name: name} = operation;
970
+ element.removeAttribute(safeString(name));
971
+ }));
972
+ after(element, operation);
973
+ }));
974
+ },
975
+ removeCssClass: operation => {
976
+ processElements(operation, (element => {
977
+ before(element, operation);
978
+ operate(operation, (() => {
979
+ const {name: name} = operation;
980
+ element.classList.remove(...getClassNames([ safeStringOrArray(name) ]));
981
+ if (element.classList.length === 0) element.removeAttribute("class");
982
+ }));
983
+ after(element, operation);
984
+ }));
985
+ },
986
+ setAttribute: operation => {
987
+ processElements(operation, (element => {
988
+ before(element, operation);
989
+ operate(operation, (() => {
990
+ const {name: name, value: value} = operation;
991
+ element.setAttribute(safeString(name), safeScalar(value));
992
+ }));
993
+ after(element, operation);
994
+ }));
995
+ },
996
+ setDatasetProperty: operation => {
997
+ processElements(operation, (element => {
998
+ before(element, operation);
999
+ operate(operation, (() => {
1000
+ const {name: name, value: value} = operation;
1001
+ element.dataset[safeString(name)] = safeScalar(value);
1002
+ }));
1003
+ after(element, operation);
1004
+ }));
1005
+ },
1006
+ setProperty: operation => {
1007
+ processElements(operation, (element => {
1008
+ before(element, operation);
1009
+ operate(operation, (() => {
1010
+ const {name: name, value: value} = operation;
1011
+ if (name in element) element[safeString(name)] = safeScalar(value);
1012
+ }));
1013
+ after(element, operation);
1014
+ }));
1015
+ },
1016
+ setStyle: operation => {
1017
+ processElements(operation, (element => {
1018
+ before(element, operation);
1019
+ operate(operation, (() => {
1020
+ const {name: name, value: value} = operation;
1021
+ element.style[safeString(name)] = safeScalar(value);
1022
+ }));
1023
+ after(element, operation);
1024
+ }));
1025
+ },
1026
+ setStyles: operation => {
1027
+ processElements(operation, (element => {
1028
+ before(element, operation);
1029
+ operate(operation, (() => {
1030
+ const {styles: styles} = operation;
1031
+ for (let [name, value] of Object.entries(styles)) element.style[safeString(name)] = safeScalar(value);
1032
+ }));
1033
+ after(element, operation);
1034
+ }));
1035
+ },
1036
+ setValue: operation => {
1037
+ processElements(operation, (element => {
1038
+ before(element, operation);
1039
+ operate(operation, (() => {
1040
+ const {value: value} = operation;
1041
+ element.value = safeScalar(value);
1042
+ }));
1043
+ after(element, operation);
1044
+ }));
1045
+ },
1046
+ dispatchEvent: operation => {
1047
+ processElements(operation, (element => {
1048
+ before(element, operation);
1049
+ operate(operation, (() => {
1050
+ const {name: name, detail: detail} = operation;
1051
+ dispatch(element, safeString(name), safeObject(detail));
1052
+ }));
1053
+ after(element, operation);
1054
+ }));
1055
+ },
1056
+ setMeta: operation => {
1057
+ before(document, operation);
1058
+ operate(operation, (() => {
1059
+ const {name: name, content: content} = operation;
1060
+ let meta = document.head.querySelector(`meta[name='${name}']`);
1061
+ if (!meta) {
1062
+ meta = document.createElement("meta");
1063
+ meta.name = safeString(name);
1064
+ document.head.appendChild(meta);
1065
+ }
1066
+ meta.content = safeScalar(content);
1067
+ }));
1068
+ after(document, operation);
1069
+ },
1070
+ setTitle: operation => {
1071
+ before(document, operation);
1072
+ operate(operation, (() => {
1073
+ const {title: title} = operation;
1074
+ document.title = safeScalar(title);
1075
+ }));
1076
+ after(document, operation);
1077
+ },
1078
+ clearStorage: operation => {
1079
+ before(document, operation);
1080
+ operate(operation, (() => {
1081
+ const {type: type} = operation;
1082
+ const storage = type === "session" ? sessionStorage : localStorage;
1083
+ storage.clear();
1084
+ }));
1085
+ after(document, operation);
1086
+ },
1087
+ go: operation => {
1088
+ before(window, operation);
1089
+ operate(operation, (() => {
1090
+ const {delta: delta} = operation;
1091
+ history.go(delta);
1092
+ }));
1093
+ after(window, operation);
1094
+ },
1095
+ pushState: operation => {
1096
+ before(window, operation);
1097
+ operate(operation, (() => {
1098
+ const {state: state, title: title, url: url} = operation;
1099
+ history.pushState(safeObject(state), safeString(title), safeString(url));
1100
+ }));
1101
+ after(window, operation);
1102
+ },
1103
+ redirectTo: operation => {
1104
+ before(window, operation);
1105
+ operate(operation, (() => {
1106
+ let {url: url, action: action, turbo: turbo} = operation;
1107
+ action = action || "advance";
1108
+ url = safeString(url);
1109
+ if (turbo === undefined) turbo = true;
1110
+ if (turbo) {
1111
+ if (window.Turbo) window.Turbo.visit(url, {
1112
+ action: action
1113
+ });
1114
+ if (window.Turbolinks) window.Turbolinks.visit(url, {
1115
+ action: action
1116
+ });
1117
+ if (!window.Turbo && !window.Turbolinks) window.location.href = url;
1118
+ } else {
1119
+ window.location.href = url;
1120
+ }
1121
+ }));
1122
+ after(window, operation);
1123
+ },
1124
+ reload: operation => {
1125
+ before(window, operation);
1126
+ operate(operation, (() => {
1127
+ window.location.reload();
1128
+ }));
1129
+ after(window, operation);
1130
+ },
1131
+ removeStorageItem: operation => {
1132
+ before(document, operation);
1133
+ operate(operation, (() => {
1134
+ const {key: key, type: type} = operation;
1135
+ const storage = type === "session" ? sessionStorage : localStorage;
1136
+ storage.removeItem(safeString(key));
1137
+ }));
1138
+ after(document, operation);
1139
+ },
1140
+ replaceState: operation => {
1141
+ before(window, operation);
1142
+ operate(operation, (() => {
1143
+ const {state: state, title: title, url: url} = operation;
1144
+ history.replaceState(safeObject(state), safeString(title), safeString(url));
1145
+ }));
1146
+ after(window, operation);
1147
+ },
1148
+ scrollIntoView: operation => {
1149
+ const {element: element} = operation;
1150
+ before(element, operation);
1151
+ operate(operation, (() => {
1152
+ element.scrollIntoView(operation);
1153
+ }));
1154
+ after(element, operation);
1155
+ },
1156
+ setCookie: operation => {
1157
+ before(document, operation);
1158
+ operate(operation, (() => {
1159
+ const {cookie: cookie} = operation;
1160
+ document.cookie = safeScalar(cookie);
1161
+ }));
1162
+ after(document, operation);
1163
+ },
1164
+ setFocus: operation => {
1165
+ const {element: element} = operation;
1166
+ before(element, operation);
1167
+ operate(operation, (() => {
1168
+ assignFocus(element);
1169
+ }));
1170
+ after(element, operation);
1171
+ },
1172
+ setStorageItem: operation => {
1173
+ before(document, operation);
1174
+ operate(operation, (() => {
1175
+ const {key: key, value: value, type: type} = operation;
1176
+ const storage = type === "session" ? sessionStorage : localStorage;
1177
+ storage.setItem(safeString(key), safeScalar(value));
1178
+ }));
1179
+ after(document, operation);
1180
+ },
1181
+ consoleLog: operation => {
1182
+ before(document, operation);
1183
+ operate(operation, (() => {
1184
+ const {message: message, level: level} = operation;
1185
+ level && [ "warn", "info", "error" ].includes(level) ? console[level](message) : console.log(message);
1186
+ }));
1187
+ after(document, operation);
1188
+ },
1189
+ consoleTable: operation => {
1190
+ before(document, operation);
1191
+ operate(operation, (() => {
1192
+ const {data: data, columns: columns} = operation;
1193
+ console.table(data, safeArray(columns));
1194
+ }));
1195
+ after(document, operation);
1196
+ },
1197
+ notification: operation => {
1198
+ before(document, operation);
1199
+ operate(operation, (() => {
1200
+ const {title: title, options: options} = operation;
1201
+ Notification.requestPermission().then((result => {
1202
+ operation.permission = result;
1203
+ if (result === "granted") new Notification(safeString(title), safeObject(options));
1204
+ }));
1205
+ }));
1206
+ after(document, operation);
1207
+ },
1208
+ morph: operation => {
1209
+ processElements(operation, (element => {
1210
+ const {html: html} = operation;
1211
+ const template = document.createElement("template");
1212
+ template.innerHTML = String(safeScalar(html)).trim();
1213
+ operation.content = template.content;
1214
+ const parent = element.parentElement;
1215
+ const idx = parent && Array.from(parent.children).indexOf(element);
1216
+ before(element, operation);
1217
+ operate(operation, (() => {
1218
+ const {childrenOnly: childrenOnly, focusSelector: focusSelector} = operation;
1219
+ morphdom(element, childrenOnly ? template.content : template.innerHTML, {
1220
+ childrenOnly: !!childrenOnly,
1221
+ onBeforeElUpdated: shouldMorph(operation),
1222
+ onElUpdated: didMorph(operation)
1223
+ });
1224
+ assignFocus(focusSelector);
1225
+ }));
1226
+ after(parent ? parent.children[idx] : document.documentElement, operation);
1227
+ }));
1228
+ }
1229
+ };
1230
+
1231
+ let operations = Operations;
1232
+
1233
+ const add = newOperations => {
1234
+ operations = {
1235
+ ...operations,
1236
+ ...newOperations
1237
+ };
1238
+ };
1239
+
1240
+ const addOperations = operations => {
1241
+ add(operations);
1242
+ };
1243
+
1244
+ const addOperation = (name, operation) => {
1245
+ const operations = {};
1246
+ operations[name] = operation;
1247
+ add(operations);
1248
+ };
1249
+
1250
+ var OperationStore = {
1251
+ get all() {
1252
+ return operations;
1253
+ }
1254
+ };
1255
+
1256
+ let missingElement = "warn";
1257
+
1258
+ var MissingElement$1 = {
1259
+ get behavior() {
1260
+ return missingElement;
1261
+ },
1262
+ set(value) {
1263
+ if ([ "warn", "ignore", "event", "exception" ].includes(value)) missingElement = value; else console.warn("Invalid 'onMissingElement' option. Defaulting to 'warn'.");
1264
+ }
1265
+ };
1266
+
1267
+ const perform = (operations, options = {
1268
+ onMissingElement: MissingElement$1.behavior
1269
+ }) => {
1270
+ const batches = {};
1271
+ operations.forEach((operation => {
1272
+ if (!!operation.batch) batches[operation.batch] = batches[operation.batch] ? ++batches[operation.batch] : 1;
1273
+ }));
1274
+ operations.forEach((operation => {
1275
+ const name = operation.operation;
1276
+ try {
1277
+ if (operation.selector) {
1278
+ if (operation.xpath) {
1279
+ operation.element = operation.selectAll ? xpathToElementArray(operation.selector) : xpathToElement(operation.selector);
1280
+ } else {
1281
+ operation.element = operation.selectAll ? document.querySelectorAll(operation.selector) : document.querySelector(operation.selector);
1282
+ }
1283
+ } else {
1284
+ operation.element = document;
1285
+ }
1286
+ if (operation.element || options.onMissingElement !== "ignore") {
1287
+ ActiveElement.set(document.activeElement);
1288
+ const cableReadyOperation = OperationStore.all[name];
1289
+ if (cableReadyOperation) {
1290
+ cableReadyOperation(operation);
1291
+ if (!!operation.batch && --batches[operation.batch] === 0) dispatch(document, "cable-ready:batch-complete", {
1292
+ batch: operation.batch
1293
+ });
1294
+ } else {
1295
+ console.error(`CableReady couldn't find the "${name}" operation. Make sure you use the camelized form when calling an operation method.`);
1296
+ }
1297
+ }
1298
+ } catch (e) {
1299
+ if (operation.element) {
1300
+ console.error(`CableReady detected an error in ${name || "operation"}: ${e.message}. If you need to support older browsers make sure you've included the corresponding polyfills. https://docs.stimulusreflex.com/setup#polyfills-for-ie11.`);
1301
+ console.error(e);
1302
+ } else {
1303
+ const warning = `CableReady ${name || ""} operation failed due to missing DOM element for selector: '${operation.selector}'`;
1304
+ switch (options.onMissingElement) {
1305
+ case "ignore":
1306
+ break;
1307
+
1308
+ case "event":
1309
+ dispatch(document, "cable-ready:missing-element", {
1310
+ warning: warning,
1311
+ operation: operation
1312
+ });
1313
+ break;
1314
+
1315
+ case "exception":
1316
+ throw warning;
1317
+
1318
+ default:
1319
+ console.warn(warning);
1320
+ }
1321
+ }
1322
+ }
1323
+ }));
1324
+ };
1325
+
1326
+ const performAsync = (operations, options = {
1327
+ onMissingElement: MissingElement$1.behavior
1328
+ }) => new Promise(((resolve, reject) => {
1329
+ try {
1330
+ resolve(perform(operations, options));
1331
+ } catch (err) {
1332
+ reject(err);
1333
+ }
1334
+ }));
1335
+
1336
+ class SubscribingElement extends HTMLElement {
1337
+ static get tagName() {
1338
+ throw new Error("Implement the tagName() getter in the inheriting class");
1339
+ }
1340
+ static define() {
1341
+ if (!customElements.get(this.tagName)) {
1342
+ customElements.define(this.tagName, this);
1343
+ }
1344
+ }
1345
+ disconnectedCallback() {
1346
+ if (this.channel) this.channel.unsubscribe();
1347
+ }
1348
+ createSubscription(consumer, channel, receivedCallback) {
1349
+ this.channel = consumer.subscriptions.create({
1350
+ channel: channel,
1351
+ identifier: this.identifier
1352
+ }, {
1353
+ received: receivedCallback
1354
+ });
1355
+ }
1356
+ get preview() {
1357
+ return document.documentElement.hasAttribute("data-turbolinks-preview") || document.documentElement.hasAttribute("data-turbo-preview");
1358
+ }
1359
+ get identifier() {
1360
+ return this.getAttribute("identifier");
1361
+ }
1362
+ }
1363
+
1364
+ let consumer;
1365
+
1366
+ const BACKOFF = [ 25, 50, 75, 100, 200, 250, 500, 800, 1e3, 2e3 ];
1367
+
1368
+ const wait = ms => new Promise((resolve => setTimeout(resolve, ms)));
1369
+
1370
+ const getConsumerWithRetry = async (retry = 0) => {
1371
+ if (consumer) return consumer;
1372
+ if (retry >= BACKOFF.length) {
1373
+ throw new Error("Couldn't obtain a Action Cable consumer within 5s");
1374
+ }
1375
+ await wait(BACKOFF[retry]);
1376
+ return await getConsumerWithRetry(retry + 1);
1377
+ };
1378
+
1379
+ var CableConsumer = {
1380
+ setConsumer(value) {
1381
+ consumer = value;
1382
+ },
1383
+ get consumer() {
1384
+ return consumer;
1385
+ },
1386
+ async getConsumer() {
1387
+ return await getConsumerWithRetry();
1388
+ }
1389
+ };
1390
+
1391
+ class StreamFromElement extends SubscribingElement {
1392
+ static get tagName() {
1393
+ return "cable-ready-stream-from";
1394
+ }
1395
+ async connectedCallback() {
1396
+ if (this.preview) return;
1397
+ const consumer = await CableConsumer.getConsumer();
1398
+ if (consumer) {
1399
+ this.createSubscription(consumer, "CableReady::Stream", this.performOperations.bind(this));
1400
+ } else {
1401
+ console.error("The `cable_ready_stream_from` helper cannot connect. You must initialize CableReady with an Action Cable consumer.");
1402
+ }
1403
+ }
1404
+ performOperations(data) {
1405
+ if (data.cableReady) perform(data.operations, {
1406
+ onMissingElement: this.onMissingElement
1407
+ });
1408
+ }
1409
+ get onMissingElement() {
1410
+ const value = this.getAttribute("missing") || MissingElement$1.behavior;
1411
+ if ([ "warn", "ignore", "event" ].includes(value)) return value; else {
1412
+ console.warn("Invalid 'missing' attribute. Defaulting to 'warn'.");
1413
+ return "warn";
1414
+ }
1415
+ }
1416
+ }
1417
+
1418
+ let debugging = false;
1419
+
1420
+ var Debug = {
1421
+ get enabled() {
1422
+ return debugging;
1423
+ },
1424
+ get disabled() {
1425
+ return !debugging;
1426
+ },
1427
+ get value() {
1428
+ return debugging;
1429
+ },
1430
+ set(value) {
1431
+ debugging = !!value;
1432
+ },
1433
+ set debug(value) {
1434
+ debugging = !!value;
1435
+ }
1436
+ };
1437
+
1438
+ const request = (data, blocks) => {
1439
+ if (Debug.disabled) return;
1440
+ const message = `↑ Updatable request affecting ${blocks.length} element(s): `;
1441
+ console.log(message, {
1442
+ elements: blocks.map((b => b.element)),
1443
+ identifiers: blocks.map((b => b.element.getAttribute("identifier"))),
1444
+ data: data
1445
+ });
1446
+ return message;
1447
+ };
1448
+
1449
+ const cancel = (timestamp, reason) => {
1450
+ if (Debug.disabled) return;
1451
+ const duration = new Date - timestamp;
1452
+ const message = `❌ Updatable request canceled after ${duration}ms: ${reason}`;
1453
+ console.log(message);
1454
+ return message;
1455
+ };
1456
+
1457
+ const response = (timestamp, element, urls) => {
1458
+ if (Debug.disabled) return;
1459
+ const duration = new Date - timestamp;
1460
+ const message = `↓ Updatable response: All URLs fetched in ${duration}ms`;
1461
+ console.log(message, {
1462
+ element: element,
1463
+ urls: urls
1464
+ });
1465
+ return message;
1466
+ };
1467
+
1468
+ const morphStart = (timestamp, element) => {
1469
+ if (Debug.disabled) return;
1470
+ const duration = new Date - timestamp;
1471
+ const message = `↻ Updatable morph: starting after ${duration}ms`;
1472
+ console.log(message, {
1473
+ element: element
1474
+ });
1475
+ return message;
1476
+ };
1477
+
1478
+ const morphEnd = (timestamp, element) => {
1479
+ if (Debug.disabled) return;
1480
+ const duration = new Date - timestamp;
1481
+ const message = `↺ Updatable morph: completed after ${duration}ms`;
1482
+ console.log(message, {
1483
+ element: element
1484
+ });
1485
+ return message;
1486
+ };
1487
+
1488
+ var Log = {
1489
+ request: request,
1490
+ cancel: cancel,
1491
+ response: response,
1492
+ morphStart: morphStart,
1493
+ morphEnd: morphEnd
1494
+ };
1495
+
1496
+ const template = `\n<style>\n :host {\n display: block;\n }\n</style>\n<slot></slot>\n`;
1497
+
1498
+ class UpdatesForElement extends SubscribingElement {
1499
+ static get tagName() {
1500
+ return "cable-ready-updates-for";
1501
+ }
1502
+ constructor() {
1503
+ super();
1504
+ const shadowRoot = this.attachShadow({
1505
+ mode: "open"
1506
+ });
1507
+ shadowRoot.innerHTML = template;
1508
+ this.triggerElementLog = new BoundedQueue(10);
1509
+ this.targetElementLog = new BoundedQueue(10);
1510
+ }
1511
+ async connectedCallback() {
1512
+ if (this.preview) return;
1513
+ this.update = debounce(this.update.bind(this), this.debounce);
1514
+ const consumer = await CableConsumer.getConsumer();
1515
+ if (consumer) {
1516
+ this.createSubscription(consumer, "CableReady::Stream", this.update);
1517
+ } else {
1518
+ console.error("The `cable_ready_updates_for` helper cannot connect. You must initialize CableReady with an Action Cable consumer.");
1519
+ }
1520
+ }
1521
+ async update(data) {
1522
+ this.lastUpdateTimestamp = new Date;
1523
+ const blocks = Array.from(document.querySelectorAll(this.query), (element => new Block(element))).filter((block => block.shouldUpdate(data)));
1524
+ this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.request(data, blocks)}`);
1525
+ if (blocks.length === 0) {
1526
+ this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.cancel(this.lastUpdateTimestamp, "All elements filtered out")}`);
1527
+ return;
1528
+ }
1529
+ if (blocks[0].element !== this) {
1530
+ this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.cancel(this.lastUpdateTimestamp, "Update already requested")}`);
1531
+ return;
1532
+ }
1533
+ ActiveElement.set(document.activeElement);
1534
+ this.html = {};
1535
+ const uniqueUrls = [ ...new Set(blocks.map((block => block.url))) ];
1536
+ await Promise.all(uniqueUrls.map((async url => {
1537
+ if (!this.html.hasOwnProperty(url)) {
1538
+ const response = await graciouslyFetch(url, {
1539
+ "X-Cable-Ready": "update"
1540
+ });
1541
+ this.html[url] = await response.text();
1542
+ }
1543
+ })));
1544
+ this.triggerElementLog.push(`${(new Date).toLocaleString()}: ${Log.response(this.lastUpdateTimestamp, this, uniqueUrls)}`);
1545
+ this.index = {};
1546
+ blocks.forEach((block => {
1547
+ this.index.hasOwnProperty(block.url) ? this.index[block.url]++ : this.index[block.url] = 0;
1548
+ block.process(data, this.html, this.index, this.lastUpdateTimestamp);
1549
+ }));
1550
+ }
1551
+ get query() {
1552
+ return `${this.tagName}[identifier="${this.identifier}"]`;
1553
+ }
1554
+ get identifier() {
1555
+ return this.getAttribute("identifier");
1556
+ }
1557
+ get debounce() {
1558
+ return this.hasAttribute("debounce") ? parseInt(this.getAttribute("debounce")) : 20;
1559
+ }
1560
+ }
1561
+
1562
+ class Block {
1563
+ constructor(element) {
1564
+ this.element = element;
1565
+ }
1566
+ async process(data, html, fragmentsIndex, startTimestamp) {
1567
+ const blockIndex = fragmentsIndex[this.url];
1568
+ const template = document.createElement("template");
1569
+ this.element.setAttribute("updating", "updating");
1570
+ template.innerHTML = String(html[this.url]).trim();
1571
+ await this.resolveTurboFrames(template.content);
1572
+ const fragments = template.content.querySelectorAll(this.query);
1573
+ if (fragments.length <= blockIndex) {
1574
+ console.warn(`Update aborted due to insufficient number of elements. The offending url is ${this.url}, the offending element is:`, this.element);
1575
+ return;
1576
+ }
1577
+ const operation = {
1578
+ element: this.element,
1579
+ html: fragments[blockIndex],
1580
+ permanentAttributeName: "data-ignore-updates"
1581
+ };
1582
+ dispatch(this.element, "cable-ready:before-update", operation);
1583
+ this.element.targetElementLog.push(`${(new Date).toLocaleString()}: ${Log.morphStart(startTimestamp, this.element)}`);
1584
+ morphdom(this.element, fragments[blockIndex], {
1585
+ childrenOnly: true,
1586
+ onBeforeElUpdated: shouldMorph(operation),
1587
+ onElUpdated: _ => {
1588
+ this.element.removeAttribute("updating");
1589
+ dispatch(this.element, "cable-ready:after-update", operation);
1590
+ assignFocus(operation.focusSelector);
1591
+ }
1592
+ });
1593
+ this.element.targetElementLog.push(`${(new Date).toLocaleString()}: ${Log.morphEnd(startTimestamp, this.element)}`);
1594
+ }
1595
+ async resolveTurboFrames(documentFragment) {
1596
+ const reloadingTurboFrames = [ ...documentFragment.querySelectorAll('turbo-frame[src]:not([loading="lazy"])') ];
1597
+ return Promise.all(reloadingTurboFrames.map((frame => new Promise((async resolve => {
1598
+ const frameResponse = await graciouslyFetch(frame.getAttribute("src"), {
1599
+ "Turbo-Frame": frame.id,
1600
+ "X-Cable-Ready": "update"
1601
+ });
1602
+ const frameTemplate = document.createElement("template");
1603
+ frameTemplate.innerHTML = await frameResponse.text();
1604
+ await this.resolveTurboFrames(frameTemplate.content);
1605
+ const selector = `turbo-frame#${frame.id}`;
1606
+ const frameContent = frameTemplate.content.querySelector(selector);
1607
+ const content = frameContent ? frameContent.innerHTML.trim() : "";
1608
+ documentFragment.querySelector(selector).innerHTML = content;
1609
+ resolve();
1610
+ })))));
1611
+ }
1612
+ shouldUpdate(data) {
1613
+ return !this.ignoresInnerUpdates && this.hasChangesSelectedForUpdate(data);
1614
+ }
1615
+ hasChangesSelectedForUpdate(data) {
1616
+ const only = this.element.getAttribute("only");
1617
+ return !(only && data.changed && !only.split(" ").some((attribute => data.changed.includes(attribute))));
1618
+ }
1619
+ get ignoresInnerUpdates() {
1620
+ return this.element.hasAttribute("ignore-inner-updates") && this.element.hasAttribute("performing-inner-update");
1621
+ }
1622
+ get url() {
1623
+ return this.element.hasAttribute("url") ? this.element.getAttribute("url") : location.href;
1624
+ }
1625
+ get identifier() {
1626
+ return this.element.identifier;
1627
+ }
1628
+ get query() {
1629
+ return this.element.query;
1630
+ }
1631
+ }
1632
+
1633
+ const registerInnerUpdates = () => {
1634
+ document.addEventListener("stimulus-reflex:before", (event => {
1635
+ recursiveMarkUpdatesForElements(event.detail.element);
1636
+ }));
1637
+ document.addEventListener("stimulus-reflex:after", (event => {
1638
+ setTimeout((() => {
1639
+ recursiveUnmarkUpdatesForElements(event.detail.element);
1640
+ }));
1641
+ }));
1642
+ document.addEventListener("turbo:submit-start", (event => {
1643
+ recursiveMarkUpdatesForElements(event.target);
1644
+ }));
1645
+ document.addEventListener("turbo:submit-end", (event => {
1646
+ setTimeout((() => {
1647
+ recursiveUnmarkUpdatesForElements(event.target);
1648
+ }));
1649
+ }));
1650
+ document.addEventListener("turbo-boost:command:start", (event => {
1651
+ recursiveMarkUpdatesForElements(event.target);
1652
+ }));
1653
+ document.addEventListener("turbo-boost:command:finish", (event => {
1654
+ setTimeout((() => {
1655
+ recursiveUnmarkUpdatesForElements(event.target);
1656
+ }));
1657
+ }));
1658
+ document.addEventListener("turbo-boost:command:error", (event => {
1659
+ setTimeout((() => {
1660
+ recursiveUnmarkUpdatesForElements(event.target);
1661
+ }));
1662
+ }));
1663
+ };
1664
+
1665
+ const recursiveMarkUpdatesForElements = leaf => {
1666
+ const closestUpdatesFor = leaf && leaf.parentElement && leaf.parentElement.closest("cable-ready-updates-for");
1667
+ if (closestUpdatesFor) {
1668
+ closestUpdatesFor.setAttribute("performing-inner-update", "");
1669
+ recursiveMarkUpdatesForElements(closestUpdatesFor);
1670
+ }
1671
+ };
1672
+
1673
+ const recursiveUnmarkUpdatesForElements = leaf => {
1674
+ const closestUpdatesFor = leaf && leaf.parentElement && leaf.parentElement.closest("cable-ready-updates-for");
1675
+ if (closestUpdatesFor) {
1676
+ closestUpdatesFor.removeAttribute("performing-inner-update");
1677
+ recursiveUnmarkUpdatesForElements(closestUpdatesFor);
1678
+ }
1679
+ };
1680
+
1681
+ const defineElements$1 = () => {
1682
+ registerInnerUpdates();
1683
+ StreamFromElement.define();
1684
+ UpdatesForElement.define();
1685
+ };
1686
+
1687
+ const initialize = (initializeOptions = {}) => {
1688
+ const {consumer: consumer, onMissingElement: onMissingElement, debug: debug} = initializeOptions;
1689
+ Debug.set(!!debug);
1690
+ if (consumer) {
1691
+ CableConsumer.setConsumer(consumer);
1692
+ } else {
1693
+ 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 })`.");
1694
+ }
1695
+ if (onMissingElement) {
1696
+ MissingElement.set(onMissingElement);
1697
+ }
1698
+ defineElements$1();
1699
+ };
1700
+
1701
+ const global = {
1702
+ perform: perform,
1703
+ performAsync: performAsync,
1704
+ shouldMorphCallbacks: shouldMorphCallbacks,
1705
+ didMorphCallbacks: didMorphCallbacks,
1706
+ initialize: initialize,
1707
+ addOperation: addOperation,
1708
+ addOperations: addOperations,
1709
+ version: packageInfo.version,
1710
+ cable: CableConsumer,
1711
+ get DOMOperations() {
1712
+ console.warn("DEPRECATED: Please use `CableReady.operations` instead of `CableReady.DOMOperations`");
1713
+ return OperationStore.all;
1714
+ },
1715
+ get operations() {
1716
+ return OperationStore.all;
1717
+ },
1718
+ get consumer() {
1719
+ return CableConsumer.consumer;
1720
+ }
1721
+ };
1722
+
1723
+ window.CableReady = global;
1724
+
1725
+ class CableReadyElement extends HTMLElement {
1726
+ static define() {
1727
+ if (!customElements.get("cable-ready")) {
1728
+ customElements.define("cable-ready", this);
1729
+ }
1730
+ }
1731
+ connectedCallback() {
1732
+ setTimeout((() => {
1733
+ try {
1734
+ const operations = JSON.parse(this.scriptElement.textContent);
1735
+ global.perform(operations);
1736
+ } catch (error) {
1737
+ console.error(error);
1738
+ } finally {
1739
+ try {
1740
+ this.remove();
1741
+ } catch {}
1742
+ }
1743
+ }));
1744
+ }
1745
+ get scriptElement() {
1746
+ if (this.firstElementChild instanceof HTMLScriptElement && this.firstElementChild.getAttribute("type") === "application/json") {
1747
+ return this.firstElementChild;
1748
+ }
1749
+ throw new Error('First child element in a `<cable-ready>` tag must be `<script type="application/json">`.');
1750
+ }
1751
+ }
1752
+
1753
+ const defineElements = () => {
1754
+ CableReadyElement.define();
1755
+ };
1756
+
1757
+ defineElements();
1758
+
1759
+ export { CableReadyElement };