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