hotwire-spark 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +27 -10
- data/app/assets/javascripts/hotwire_spark.js +101 -69
- data/app/assets/javascripts/hotwire_spark.min.js +1 -1
- data/app/assets/javascripts/hotwire_spark.min.js.map +1 -1
- data/app/controllers/hotwire/spark/source_files_controller.rb +14 -0
- data/app/javascript/hotwire/spark/channels/monitoring_channel.js +10 -9
- data/app/javascript/hotwire/spark/index.js +10 -2
- data/app/javascript/hotwire/spark/reloaders/{html_reloader.js → morph_html_reloader.js} +8 -8
- data/app/javascript/hotwire/spark/reloaders/replace_html_reloader.js +31 -0
- data/app/javascript/hotwire/spark/reloaders/stimulus_reloader.js +49 -59
- data/config/routes.rb +1 -0
- data/lib/hotwire/spark/default_options.rb +36 -0
- data/lib/hotwire/spark/engine.rb +2 -5
- data/lib/hotwire/spark/file_watcher.rb +5 -1
- data/lib/hotwire/spark/installer.rb +17 -6
- data/lib/hotwire/spark/middleware.rb +12 -7
- data/lib/hotwire/spark/version.rb +1 -1
- data/lib/hotwire-spark.rb +6 -3
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86280ef674a47bc00119c73166435a363c34e6c22804444df25d8f909fe5755c
|
4
|
+
data.tar.gz: 016b6bc8f6bf0f22bf3cec4baa754a167fdc526230f0a57df83c1f0916ee4f56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be78aab02729c9f00b86f366ce7ff2813dab842a2e1b78699d19dfaaf11b61a98e31269cb625939c4a8204fa3c6c3b0f51548098ff4df3cd78d1eee91dfd26b6
|
7
|
+
data.tar.gz: ef71e4ecbb78de1dcfe7b2224e40b7d41455a2da4feb3cbf0967664acd7d8eb8a9e5b3cae7a9fbba48c1647eda661249d7c9866de595e12cc186a4471323eb8c
|
data/README.md
CHANGED
@@ -24,12 +24,25 @@ That's it!
|
|
24
24
|
|
25
25
|
The system will listen for three kinds of changes and will take action depending on each:
|
26
26
|
|
27
|
-
*
|
27
|
+
* HTML contents
|
28
|
+
* CSS
|
29
|
+
* Stimulus controllers
|
30
|
+
|
31
|
+
Depending on your setup, the default behavior will be different.
|
32
|
+
|
33
|
+
### Importmaps
|
34
|
+
|
35
|
+
Importmaps allows for the smoother updates because it supports hot-reloading for Stimulus controllers:
|
36
|
+
|
37
|
+
* **HTML change:** it fetches the new document body and updates the current body with morphing, then it reloads the Stimulus controllers in the page. It uses [`idiomorph`](https://github.com/bigskysoftware/idiomorph) under the hood.
|
28
38
|
* **CSS change:** it fetches and reloads the stylesheet that changed.
|
29
39
|
* **Stimulus controller change:** it fetches the Stimulus controller that changed and reloads all the controllers in the page.
|
30
40
|
|
31
|
-
|
32
|
-
|
41
|
+
### JavaScript Bundling
|
42
|
+
|
43
|
+
* **HTML change:** it reloads the page with a Turbo visit.
|
44
|
+
* **CSS change:** it fetches and reloads the stylesheet that changed.
|
45
|
+
* **Stimulus controller change:** it reloads the page with a Turbo visit.
|
33
46
|
|
34
47
|
## Configuration
|
35
48
|
|
@@ -39,13 +52,17 @@ You can set configuration options on your `development.rb`. For example:
|
|
39
52
|
config.hotwire.spark.html_paths += %w[ lib ]
|
40
53
|
```
|
41
54
|
|
42
|
-
| Name
|
43
|
-
|
44
|
-
| `html_paths`
|
45
|
-
| `css_paths`
|
46
|
-
| `stimulus_paths`
|
47
|
-
| `enabled`
|
48
|
-
| `logging`
|
55
|
+
| Name | Description |
|
56
|
+
|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
57
|
+
| `html_paths` | Paths where file changes trigger a content refresh. By default: `app/controllers`, `app/helpers`, `app/models`, `app/views`. |
|
58
|
+
| `css_paths` | Paths where file changes trigger a CSS refresh. By default: `app/assets/stylesheets` or `app/assets/builds` if exists. |
|
59
|
+
| `stimulus_paths` | Paths where file changes trigger a Stimulus controller refresh. By default: `app/javascript/controllers`. |
|
60
|
+
| `enabled` | Enable or disable live reloading. By default, it's only enabled in `development`. |
|
61
|
+
| `logging` | Show logs in the browser console when reloading happens. It's false by default. |
|
62
|
+
| `html_reload_method` | How to perform reloads when HTML content changes: `:morph` or `:replace`. By default, it is `:morph` and it will morph the `<body>` of the page and reload all the stimulus controllers. Set to `:replace` to reload the page with a regular Turbo navigation that will replace the `<body>`. |
|
63
|
+
| `html_extensions` | The extension to monitor for HTML content changes. By default: `rb`, `erb`. | |
|
64
|
+
| `css_extensions` | The extension to monitor for CSS changes. By default: `css`. | |
|
65
|
+
| `stimulus_extensions` | The extension to monitor for CSS changes. By default: `js`. | |
|
49
66
|
|
50
67
|
## License
|
51
68
|
|
@@ -1387,7 +1387,7 @@ var HotwireSpark = (function () {
|
|
1387
1387
|
})();
|
1388
1388
|
|
1389
1389
|
function log() {
|
1390
|
-
if (HotwireSpark.config.loggingEnabled) {
|
1390
|
+
if (HotwireSpark$1.config.loggingEnabled) {
|
1391
1391
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
1392
1392
|
args[_key] = arguments[_key];
|
1393
1393
|
}
|
@@ -1396,71 +1396,64 @@ var HotwireSpark = (function () {
|
|
1396
1396
|
}
|
1397
1397
|
|
1398
1398
|
class StimulusReloader {
|
1399
|
-
static async reload(
|
1400
|
-
|
1401
|
-
return new StimulusReloader(document, filePattern).reload();
|
1399
|
+
static async reload(path) {
|
1400
|
+
return new StimulusReloader(path).reload();
|
1402
1401
|
}
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1402
|
+
static async reloadAll() {
|
1403
|
+
Stimulus.controllers.forEach(controller => {
|
1404
|
+
Stimulus.unload(controller.identifier);
|
1405
|
+
Stimulus.register(controller.identifier, controller.constructor);
|
1406
|
+
});
|
1407
|
+
return Promise.resolve();
|
1408
|
+
}
|
1409
|
+
constructor(changedPath) {
|
1410
|
+
this.changedPath = changedPath;
|
1407
1411
|
this.application = window.Stimulus;
|
1408
1412
|
}
|
1409
1413
|
async reload() {
|
1410
1414
|
log("Reload Stimulus controllers...");
|
1411
1415
|
this.application.stop();
|
1412
|
-
|
1413
|
-
|
1416
|
+
try {
|
1417
|
+
await this.#reloadChangedController();
|
1418
|
+
} catch (error) {
|
1419
|
+
if (error instanceof SourceFileNotFound) {
|
1420
|
+
this.#deregisterChangedController();
|
1421
|
+
} else {
|
1422
|
+
console.error("Error reloading controller", error);
|
1423
|
+
}
|
1424
|
+
}
|
1414
1425
|
this.application.start();
|
1415
1426
|
}
|
1416
|
-
async #
|
1417
|
-
|
1418
|
-
|
1419
|
-
get #stimulusControllerPathsToReload() {
|
1420
|
-
this.controllerPathsToReload = this.controllerPathsToReload || this.#stimulusControllerPaths.filter(path => this.#shouldReloadController(path));
|
1421
|
-
return this.controllerPathsToReload;
|
1427
|
+
async #reloadChangedController() {
|
1428
|
+
const module = await this.#importControllerFromSource(this.changedPath);
|
1429
|
+
await this.#registerController(this.#changedControllerIdentifier, module);
|
1422
1430
|
}
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
return this.filePattern.test(path);
|
1428
|
-
}
|
1429
|
-
get #stimulusPathsByModule() {
|
1430
|
-
this.pathsByModule = this.pathsByModule || this.#parseImportmapJson();
|
1431
|
-
return this.pathsByModule;
|
1432
|
-
}
|
1433
|
-
#parseImportmapJson() {
|
1434
|
-
const importmapScript = this.document.querySelector("script[type=importmap]");
|
1435
|
-
return JSON.parse(importmapScript.text).imports;
|
1436
|
-
}
|
1437
|
-
async #reloadStimulusController(moduleName) {
|
1438
|
-
log(`\t${moduleName}`);
|
1439
|
-
const controllerName = this.#extractControllerName(moduleName);
|
1440
|
-
const path = cacheBustedUrl(this.#pathForModuleName(moduleName));
|
1441
|
-
const module = await import(path);
|
1442
|
-
this.#registerController(controllerName, module);
|
1443
|
-
}
|
1444
|
-
#unloadDeletedStimulusControllers() {
|
1445
|
-
this.#controllersToUnload.forEach(controller => this.#deregisterController(controller.identifier));
|
1446
|
-
}
|
1447
|
-
get #controllersToUnload() {
|
1448
|
-
if (this.#didChangeTriggerAReload) {
|
1449
|
-
return [];
|
1450
|
-
} else {
|
1451
|
-
return this.application.controllers.filter(controller => this.filePattern.test(`${controller.identifier}_controller`));
|
1431
|
+
async #importControllerFromSource(path) {
|
1432
|
+
const response = await fetch(`/spark/source_files/?path=${path}`);
|
1433
|
+
if (response.status === 404) {
|
1434
|
+
throw new SourceFileNotFound(`Source file not found: ${path}`);
|
1452
1435
|
}
|
1436
|
+
const sourceCode = await response.text();
|
1437
|
+
const blob = new Blob([sourceCode], {
|
1438
|
+
type: "application/javascript"
|
1439
|
+
});
|
1440
|
+
const moduleUrl = URL.createObjectURL(blob);
|
1441
|
+
const module = await import(moduleUrl);
|
1442
|
+
URL.revokeObjectURL(moduleUrl);
|
1443
|
+
return module;
|
1453
1444
|
}
|
1454
|
-
get #
|
1455
|
-
|
1456
|
-
|
1457
|
-
#pathForModuleName(moduleName) {
|
1458
|
-
return this.#stimulusPathsByModule[moduleName];
|
1445
|
+
get #changedControllerIdentifier() {
|
1446
|
+
this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.changedPath);
|
1447
|
+
return this.changedControllerIdentifier;
|
1459
1448
|
}
|
1460
1449
|
#extractControllerName(path) {
|
1461
|
-
return path.replace(/^.*\//, "").replace("_controller", "").replace(/\//g, "--").replace(/_/g, "-");
|
1450
|
+
return path.replace(/^.*\//, "").replace("_controller", "").replace(/\//g, "--").replace(/_/g, "-").replace(/\.js$/, "");
|
1451
|
+
}
|
1452
|
+
#deregisterChangedController() {
|
1453
|
+
this.#deregisterController(this.#changedControllerIdentifier);
|
1462
1454
|
}
|
1463
1455
|
#registerController(name, module) {
|
1456
|
+
log("\tReloading controller", name);
|
1464
1457
|
this.application.unload(name);
|
1465
1458
|
this.application.register(name, module.default);
|
1466
1459
|
}
|
@@ -1469,17 +1462,18 @@ var HotwireSpark = (function () {
|
|
1469
1462
|
this.application.unload(name);
|
1470
1463
|
}
|
1471
1464
|
}
|
1465
|
+
class SourceFileNotFound extends Error {}
|
1472
1466
|
|
1473
|
-
class
|
1467
|
+
class MorphHtmlReloader {
|
1474
1468
|
static async reload() {
|
1475
|
-
return new
|
1469
|
+
return new MorphHtmlReloader().reload();
|
1476
1470
|
}
|
1477
1471
|
async reload() {
|
1478
|
-
|
1479
|
-
await this.#reloadStimulus(
|
1472
|
+
await this.#reloadHtml();
|
1473
|
+
await this.#reloadStimulus();
|
1480
1474
|
}
|
1481
1475
|
async #reloadHtml() {
|
1482
|
-
log("Reload html...");
|
1476
|
+
log("Reload html with morph...");
|
1483
1477
|
const reloadedDocument = await reloadHtmlDocument();
|
1484
1478
|
this.#updateBody(reloadedDocument.body);
|
1485
1479
|
return reloadedDocument;
|
@@ -1487,8 +1481,8 @@ var HotwireSpark = (function () {
|
|
1487
1481
|
#updateBody(newBody) {
|
1488
1482
|
Idiomorph.morph(document.body, newBody);
|
1489
1483
|
}
|
1490
|
-
async #reloadStimulus(
|
1491
|
-
|
1484
|
+
async #reloadStimulus() {
|
1485
|
+
await StimulusReloader.reloadAll();
|
1492
1486
|
}
|
1493
1487
|
}
|
1494
1488
|
|
@@ -1548,6 +1542,35 @@ var HotwireSpark = (function () {
|
|
1548
1542
|
}
|
1549
1543
|
}
|
1550
1544
|
|
1545
|
+
class ReplaceHtmlReloader {
|
1546
|
+
static async reload() {
|
1547
|
+
return new ReplaceHtmlReloader().reload();
|
1548
|
+
}
|
1549
|
+
async reload() {
|
1550
|
+
await this.#reloadHtml();
|
1551
|
+
}
|
1552
|
+
async #reloadHtml() {
|
1553
|
+
log("Reload html with Turbo...");
|
1554
|
+
this.#maintainScrollPosition();
|
1555
|
+
await this.#visitCurrentPage();
|
1556
|
+
}
|
1557
|
+
#maintainScrollPosition() {
|
1558
|
+
document.addEventListener("turbo:before-render", () => {
|
1559
|
+
Turbo.navigator.currentVisit.scrolled = true;
|
1560
|
+
}, {
|
1561
|
+
once: true
|
1562
|
+
});
|
1563
|
+
}
|
1564
|
+
#visitCurrentPage() {
|
1565
|
+
return new Promise(resolve => {
|
1566
|
+
document.addEventListener("turbo:load", () => resolve(document), {
|
1567
|
+
once: true
|
1568
|
+
});
|
1569
|
+
window.Turbo.visit(window.location);
|
1570
|
+
});
|
1571
|
+
}
|
1572
|
+
}
|
1573
|
+
|
1551
1574
|
consumer.subscriptions.create({
|
1552
1575
|
channel: "Hotwire::Spark::Channel"
|
1553
1576
|
}, {
|
@@ -1566,38 +1589,47 @@ var HotwireSpark = (function () {
|
|
1566
1589
|
action,
|
1567
1590
|
path
|
1568
1591
|
} = _ref;
|
1569
|
-
const fileName = assetNameFromPath(path);
|
1570
1592
|
switch (action) {
|
1571
1593
|
case "reload_html":
|
1572
1594
|
return this.reloadHtml();
|
1573
1595
|
case "reload_css":
|
1574
|
-
return this.reloadCss(
|
1596
|
+
return this.reloadCss(path);
|
1575
1597
|
case "reload_stimulus":
|
1576
|
-
return this.reloadStimulus(
|
1598
|
+
return this.reloadStimulus(path);
|
1577
1599
|
default:
|
1578
1600
|
throw new Error(`Unknown action: ${action}`);
|
1579
1601
|
}
|
1580
1602
|
},
|
1581
1603
|
reloadHtml() {
|
1582
|
-
|
1604
|
+
const htmlReloader = HotwireSpark.config.htmlReloadMethod == "morph" ? MorphHtmlReloader : ReplaceHtmlReloader;
|
1605
|
+
return htmlReloader.reload();
|
1583
1606
|
},
|
1584
|
-
reloadCss(
|
1607
|
+
reloadCss(path) {
|
1608
|
+
const fileName = assetNameFromPath(path);
|
1585
1609
|
return CssReloader.reload(new RegExp(fileName));
|
1586
1610
|
},
|
1587
|
-
reloadStimulus(
|
1588
|
-
return StimulusReloader.reload(
|
1611
|
+
reloadStimulus(path) {
|
1612
|
+
return StimulusReloader.reload(path);
|
1589
1613
|
}
|
1590
1614
|
});
|
1591
1615
|
|
1592
|
-
const HotwireSpark = {
|
1616
|
+
const HotwireSpark$1 = {
|
1593
1617
|
config: {
|
1594
|
-
loggingEnabled: false
|
1618
|
+
loggingEnabled: false,
|
1619
|
+
htmlReloadMethod: "morph"
|
1595
1620
|
}
|
1596
1621
|
};
|
1622
|
+
const configProperties = {
|
1623
|
+
loggingEnabled: "logging",
|
1624
|
+
htmlReloadMethod: "html-reload-method"
|
1625
|
+
};
|
1597
1626
|
document.addEventListener("DOMContentLoaded", function () {
|
1598
|
-
|
1627
|
+
Object.entries(configProperties).forEach(_ref => {
|
1628
|
+
let [key, property] = _ref;
|
1629
|
+
HotwireSpark$1.config[key] = getConfigurationProperty(property);
|
1630
|
+
});
|
1599
1631
|
});
|
1600
1632
|
|
1601
|
-
return HotwireSpark;
|
1633
|
+
return HotwireSpark$1;
|
1602
1634
|
|
1603
1635
|
})();
|
@@ -1,2 +1,2 @@
|
|
1
|
-
var HotwireSpark=function(){"use strict";var e={logger:"undefined"!=typeof console?console:void 0,WebSocket:"undefined"!=typeof WebSocket?WebSocket:void 0},t={log(...t){this.enabled&&(t.push(Date.now()),e.logger.log("[ActionCable]",...t))}};const n=()=>(new Date).getTime(),o=e=>(n()-e)/1e3;class i{constructor(e){this.visibilityDidChange=this.visibilityDidChange.bind(this),this.connection=e,this.reconnectAttempts=0}start(){this.isRunning()||(this.startedAt=n(),delete this.stoppedAt,this.startPolling(),addEventListener("visibilitychange",this.visibilityDidChange),t.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`))}stop(){this.isRunning()&&(this.stoppedAt=n(),this.stopPolling(),removeEventListener("visibilitychange",this.visibilityDidChange),t.log("ConnectionMonitor stopped"))}isRunning(){return this.startedAt&&!this.stoppedAt}recordMessage(){this.pingedAt=n()}recordConnect(){this.reconnectAttempts=0,delete this.disconnectedAt,t.log("ConnectionMonitor recorded connect")}recordDisconnect(){this.disconnectedAt=n(),t.log("ConnectionMonitor recorded disconnect")}startPolling(){this.stopPolling(),this.poll()}stopPolling(){clearTimeout(this.pollTimeout)}poll(){this.pollTimeout=setTimeout((()=>{this.reconnectIfStale(),this.poll()}),this.getPollInterval())}getPollInterval(){const{staleThreshold:e,reconnectionBackoffRate:t}=this.constructor;return 1e3*e*Math.pow(1+t,Math.min(this.reconnectAttempts,10))*(1+(0===this.reconnectAttempts?1:t)*Math.random())}reconnectIfStale(){this.connectionIsStale()&&(t.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${o(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`),this.reconnectAttempts++,this.disconnectedRecently()?t.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${o(this.disconnectedAt)} s`):(t.log("ConnectionMonitor reopening"),this.connection.reopen()))}get refreshedAt(){return this.pingedAt?this.pingedAt:this.startedAt}connectionIsStale(){return o(this.refreshedAt)>this.constructor.staleThreshold}disconnectedRecently(){return this.disconnectedAt&&o(this.disconnectedAt)<this.constructor.staleThreshold}visibilityDidChange(){"visible"===document.visibilityState&&setTimeout((()=>{!this.connectionIsStale()&&this.connection.isOpen()||(t.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`),this.connection.reopen())}),200)}}i.staleThreshold=6,i.reconnectionBackoffRate=.15;var r={message_types:{welcome:"welcome",disconnect:"disconnect",ping:"ping",confirmation:"confirm_subscription",rejection:"reject_subscription"},disconnect_reasons:{unauthorized:"unauthorized",invalid_request:"invalid_request",server_restart:"server_restart",remote:"remote"},default_mount_path:"/cable",protocols:["actioncable-v1-json","actioncable-unsupported"]};const{message_types:s,protocols:l}=r,c=l.slice(0,l.length-1),a=[].indexOf;class u{constructor(e){this.open=this.open.bind(this),this.consumer=e,this.subscriptions=this.consumer.subscriptions,this.monitor=new i(this),this.disconnected=!0}send(e){return!!this.isOpen()&&(this.webSocket.send(JSON.stringify(e)),!0)}open(){if(this.isActive())return t.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`),!1;{const n=[...l,...this.consumer.subprotocols||[]];return t.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${n}`),this.webSocket&&this.uninstallEventHandlers(),this.webSocket=new e.WebSocket(this.consumer.url,n),this.installEventHandlers(),this.monitor.start(),!0}}close({allowReconnect:e}={allowReconnect:!0}){if(e||this.monitor.stop(),this.isOpen())return this.webSocket.close()}reopen(){if(t.log(`Reopening WebSocket, current state is ${this.getState()}`),!this.isActive())return this.open();try{return this.close()}catch(e){t.log("Failed to reopen WebSocket",e)}finally{t.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`),setTimeout(this.open,this.constructor.reopenDelay)}}getProtocol(){if(this.webSocket)return this.webSocket.protocol}isOpen(){return this.isState("open")}isActive(){return this.isState("open","connecting")}triedToReconnect(){return this.monitor.reconnectAttempts>0}isProtocolSupported(){return a.call(c,this.getProtocol())>=0}isState(...e){return a.call(e,this.getState())>=0}getState(){if(this.webSocket)for(let t in e.WebSocket)if(e.WebSocket[t]===this.webSocket.readyState)return t.toLowerCase();return null}installEventHandlers(){for(let e in this.events){const t=this.events[e].bind(this);this.webSocket[`on${e}`]=t}}uninstallEventHandlers(){for(let e in this.events)this.webSocket[`on${e}`]=function(){}}}u.reopenDelay=500,u.prototype.events={message(e){if(!this.isProtocolSupported())return;const{identifier:n,message:o,reason:i,reconnect:r,type:l}=JSON.parse(e.data);switch(this.monitor.recordMessage(),l){case s.welcome:return this.triedToReconnect()&&(this.reconnectAttempted=!0),this.monitor.recordConnect(),this.subscriptions.reload();case s.disconnect:return t.log(`Disconnecting. Reason: ${i}`),this.close({allowReconnect:r});case s.ping:return null;case s.confirmation:return this.subscriptions.confirmSubscription(n),this.reconnectAttempted?(this.reconnectAttempted=!1,this.subscriptions.notify(n,"connected",{reconnected:!0})):this.subscriptions.notify(n,"connected",{reconnected:!1});case s.rejection:return this.subscriptions.reject(n);default:return this.subscriptions.notify(n,"received",o)}},open(){if(t.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`),this.disconnected=!1,!this.isProtocolSupported())return t.log("Protocol is unsupported. Stopping monitor and disconnecting."),this.close({allowReconnect:!1})},close(e){if(t.log("WebSocket onclose event"),!this.disconnected)return this.disconnected=!0,this.monitor.recordDisconnect(),this.subscriptions.notifyAll("disconnected",{willAttemptReconnect:this.monitor.isRunning()})},error(){t.log("WebSocket onerror event")}};class d{constructor(e,t={},n){this.consumer=e,this.identifier=JSON.stringify(t),function(e,t){if(null!=t)for(let n in t){const o=t[n];e[n]=o}}(this,n)}perform(e,t={}){return t.action=e,this.send(t)}send(e){return this.consumer.send({command:"message",identifier:this.identifier,data:JSON.stringify(e)})}unsubscribe(){return this.consumer.subscriptions.remove(this)}}class h{constructor(e){this.subscriptions=e,this.pendingSubscriptions=[]}guarantee(e){-1==this.pendingSubscriptions.indexOf(e)?(t.log(`SubscriptionGuarantor guaranteeing ${e.identifier}`),this.pendingSubscriptions.push(e)):t.log(`SubscriptionGuarantor already guaranteeing ${e.identifier}`),this.startGuaranteeing()}forget(e){t.log(`SubscriptionGuarantor forgetting ${e.identifier}`),this.pendingSubscriptions=this.pendingSubscriptions.filter((t=>t!==e))}startGuaranteeing(){this.stopGuaranteeing(),this.retrySubscribing()}stopGuaranteeing(){clearTimeout(this.retryTimeout)}retrySubscribing(){this.retryTimeout=setTimeout((()=>{this.subscriptions&&"function"==typeof this.subscriptions.subscribe&&this.pendingSubscriptions.map((e=>{t.log(`SubscriptionGuarantor resubscribing ${e.identifier}`),this.subscriptions.subscribe(e)}))}),500)}}class p{constructor(e){this.consumer=e,this.guarantor=new h(this),this.subscriptions=[]}create(e,t){const n="object"==typeof e?e:{channel:e},o=new d(this.consumer,n,t);return this.add(o)}add(e){return this.subscriptions.push(e),this.consumer.ensureActiveConnection(),this.notify(e,"initialized"),this.subscribe(e),e}remove(e){return this.forget(e),this.findAll(e.identifier).length||this.sendCommand(e,"unsubscribe"),e}reject(e){return this.findAll(e).map((e=>(this.forget(e),this.notify(e,"rejected"),e)))}forget(e){return this.guarantor.forget(e),this.subscriptions=this.subscriptions.filter((t=>t!==e)),e}findAll(e){return this.subscriptions.filter((t=>t.identifier===e))}reload(){return this.subscriptions.map((e=>this.subscribe(e)))}notifyAll(e,...t){return this.subscriptions.map((n=>this.notify(n,e,...t)))}notify(e,t,...n){let o;return o="string"==typeof e?this.findAll(e):[e],o.map((e=>"function"==typeof e[t]?e[t](...n):void 0))}subscribe(e){this.sendCommand(e,"subscribe")&&this.guarantor.guarantee(e)}confirmSubscription(e){t.log(`Subscription confirmed ${e}`),this.findAll(e).map((e=>this.guarantor.forget(e)))}sendCommand(e,t){const{identifier:n}=e;return this.consumer.send({command:t,identifier:n})}}class f{constructor(e){this._url=e,this.subscriptions=new p(this),this.connection=new u(this),this.subprotocols=[]}get url(){return function(e){"function"==typeof e&&(e=e());if(e&&!/^wss?:/i.test(e)){const t=document.createElement("a");return t.href=e,t.href=t.href,t.protocol=t.protocol.replace("http","ws"),t.href}return e}(this._url)}send(e){return this.connection.send(e)}connect(){return this.connection.open()}disconnect(){return this.connection.close({allowReconnect:!1})}ensureActiveConnection(){if(!this.connection.isActive())return this.connection.open()}addSubProtocol(e){this.subprotocols=[...this.subprotocols,e]}}var m=function(e=function(e){const t=document.head.querySelector(`meta[name='action-cable-${e}']`);if(t)return t.getAttribute("content")}("url")||r.default_mount_path){return new f(e)}("/hotwire-spark");function g(e){return e.replace(/-[a-z0-9]+\.(\w+)(\?.*)?$/,".$1")}function b(e,t){const n=new URL(e,window.location.origin);return Object.entries(t).forEach((e=>{let[t,o]=e;n.searchParams.set(t,o)})),n.toString()}function v(e){return b(e,{reload:Date.now()})}async function y(){let e=v(b(window.location.href,{hotwire_spark:"true"}));const t=await fetch(e,{headers:{Accept:"text/html"}});if(!t.ok)throw new Error(`${t.status} when fetching ${e}`);const n=await t.text();return(new DOMParser).parseFromString(n,"text/html")}var S=function(){let e=new Set,t={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:a,afterNodeAdded:a,beforeNodeMorphed:a,afterNodeMorphed:a,beforeNodeRemoved:a,afterNodeRemoved:a,beforeAttributeUpdated:a},head:{style:"merge",shouldPreserve:function(e){return"true"===e.getAttribute("im-preserve")},shouldReAppend:function(e){return"true"===e.getAttribute("im-re-append")},shouldRemove:a,afterHeadMorphed:a}};function n(e,t,o){if(o.head.block){let i=e.querySelector("head"),r=t.querySelector("head");if(i&&r){let s=c(r,i,o);return void Promise.all(s).then((function(){n(e,t,Object.assign(o,{head:{block:!1,ignore:!0}}))}))}}if("innerHTML"===o.morphStyle)return r(t,e,o),e.children;if("outerHTML"===o.morphStyle||null==o.morphStyle){let n=function(e,t,n){let o;o=e.firstChild;let i=o,r=0;for(;o;){let e=m(o,t,n);e>r&&(i=o,r=e),o=o.nextSibling}return i}(t,e,o),r=n?.previousSibling,s=n?.nextSibling,l=i(e,n,o);return n?function(e,t,n){let o=[],i=[];for(;null!=e;)o.push(e),e=e.previousSibling;for(;o.length>0;){let e=o.pop();i.push(e),t.parentElement.insertBefore(e,t)}i.push(t);for(;null!=n;)o.push(n),i.push(n),n=n.nextSibling;for(;o.length>0;)t.parentElement.insertBefore(o.pop(),t.nextSibling);return i}(r,l,s):[]}throw"Do not understand how to morph style "+o.morphStyle}function o(e,t){return t.ignoreActiveValue&&e===document.activeElement}function i(e,t,n){if(!n.ignoreActive||e!==document.activeElement)return null==t?!1===n.callbacks.beforeNodeRemoved(e)?e:(e.remove(),n.callbacks.afterNodeRemoved(e),null):d(e,t)?(!1===n.callbacks.beforeNodeMorphed(e,t)||(e instanceof HTMLHeadElement&&n.head.ignore||(e instanceof HTMLHeadElement&&"morph"!==n.head.style?c(t,e,n):(!function(e,t,n){let i=e.nodeType;if(1===i){const o=e.attributes,i=t.attributes;for(const e of o)s(e.name,t,"update",n)||t.getAttribute(e.name)!==e.value&&t.setAttribute(e.name,e.value);for(let o=i.length-1;0<=o;o--){const r=i[o];s(r.name,t,"remove",n)||(e.hasAttribute(r.name)||t.removeAttribute(r.name))}}8!==i&&3!==i||t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue);o(t,n)||function(e,t,n){if(e instanceof HTMLInputElement&&t instanceof HTMLInputElement&&"file"!==e.type){let o=e.value,i=t.value;l(e,t,"checked",n),l(e,t,"disabled",n),e.hasAttribute("value")?o!==i&&(s("value",t,"update",n)||(t.setAttribute("value",o),t.value=o)):s("value",t,"remove",n)||(t.value="",t.removeAttribute("value"))}else if(e instanceof HTMLOptionElement)l(e,t,"selected",n);else if(e instanceof HTMLTextAreaElement&&t instanceof HTMLTextAreaElement){let o=e.value,i=t.value;if(s("value",t,"update",n))return;o!==i&&(t.value=o),t.firstChild&&t.firstChild.nodeValue!==o&&(t.firstChild.nodeValue=o)}}(e,t,n)}(t,e,n),o(e,n)||r(t,e,n))),n.callbacks.afterNodeMorphed(e,t)),e):!1===n.callbacks.beforeNodeRemoved(e)||!1===n.callbacks.beforeNodeAdded(t)?e:(e.parentElement.replaceChild(t,e),n.callbacks.afterNodeAdded(t),n.callbacks.afterNodeRemoved(e),t)}function r(e,t,n){let o,r=e.firstChild,s=t.firstChild;for(;r;){if(o=r,r=o.nextSibling,null==s){if(!1===n.callbacks.beforeNodeAdded(o))return;t.appendChild(o),n.callbacks.afterNodeAdded(o),y(n,o);continue}if(u(o,s,n)){i(s,o,n),s=s.nextSibling,y(n,o);continue}let l=p(e,t,o,s,n);if(l){s=h(s,l,n),i(l,o,n),y(n,o);continue}let c=f(e,t,o,s,n);if(c)s=h(s,c,n),i(c,o,n),y(n,o);else{if(!1===n.callbacks.beforeNodeAdded(o))return;t.insertBefore(o,s),n.callbacks.afterNodeAdded(o),y(n,o)}}for(;null!==s;){let e=s;s=s.nextSibling,g(e,n)}}function s(e,t,n,o){return!("value"!==e||!o.ignoreActiveValue||t!==document.activeElement)||!1===o.callbacks.beforeAttributeUpdated(e,t,n)}function l(e,t,n,o){if(e[n]!==t[n]){let i=s(n,t,"update",o);i||(t[n]=e[n]),e[n]?i||t.setAttribute(n,e[n]):s(n,t,"remove",o)||t.removeAttribute(n)}}function c(e,t,n){let o=[],i=[],r=[],s=[],l=n.head.style,c=new Map;for(const t of e.children)c.set(t.outerHTML,t);for(const e of t.children){let t=c.has(e.outerHTML),o=n.head.shouldReAppend(e),a=n.head.shouldPreserve(e);t||a?o?i.push(e):(c.delete(e.outerHTML),r.push(e)):"append"===l?o&&(i.push(e),s.push(e)):!1!==n.head.shouldRemove(e)&&i.push(e)}s.push(...c.values());let a=[];for(const e of s){let i=document.createRange().createContextualFragment(e.outerHTML).firstChild;if(!1!==n.callbacks.beforeNodeAdded(i)){if(i.href||i.src){let e=null,t=new Promise((function(t){e=t}));i.addEventListener("load",(function(){e()})),a.push(t)}t.appendChild(i),n.callbacks.afterNodeAdded(i),o.push(i)}}for(const e of i)!1!==n.callbacks.beforeNodeRemoved(e)&&(t.removeChild(e),n.callbacks.afterNodeRemoved(e));return n.head.afterHeadMorphed(t,{added:o,kept:r,removed:i}),a}function a(){}function u(e,t,n){return null!=e&&null!=t&&(e.nodeType===t.nodeType&&e.tagName===t.tagName&&(""!==e.id&&e.id===t.id||S(n,e,t)>0))}function d(e,t){return null!=e&&null!=t&&(e.nodeType===t.nodeType&&e.tagName===t.tagName)}function h(e,t,n){for(;e!==t;){let t=e;e=e.nextSibling,g(t,n)}return y(n,t),t.nextSibling}function p(e,t,n,o,i){let r=S(i,n,t);if(r>0){let t=o,s=0;for(;null!=t;){if(u(n,t,i))return t;if(s+=S(i,t,e),s>r)return null;t=t.nextSibling}}return null}function f(e,t,n,o,i){let r=o,s=n.nextSibling,l=0;for(;null!=r;){if(S(i,r,e)>0)return null;if(d(n,r))return r;if(d(s,r)&&(l++,s=s.nextSibling,l>=2))return null;r=r.nextSibling}return r}function m(e,t,n){return d(e,t)?.5+S(n,e,t):0}function g(e,t){y(t,e),!1!==t.callbacks.beforeNodeRemoved(e)&&(e.remove(),t.callbacks.afterNodeRemoved(e))}function b(e,t){return!e.deadIds.has(t)}function v(t,n,o){return(t.idMap.get(o)||e).has(n)}function y(t,n){let o=t.idMap.get(n)||e;for(const e of o)t.deadIds.add(e)}function S(t,n,o){let i=t.idMap.get(n)||e,r=0;for(const e of i)b(t,e)&&v(t,e,o)&&++r;return r}function A(e,t){let n=e.parentElement,o=e.querySelectorAll("[id]");for(const e of o){let o=e;for(;o!==n&&null!=o;){let n=t.get(o);null==n&&(n=new Set,t.set(o,n)),n.add(e.id),o=o.parentElement}}}function w(e,t){let n=new Map;return A(e,n),A(t,n),n}return{morph:function(e,o,i={}){e instanceof Document&&(e=e.documentElement),"string"==typeof o&&(o=function(e){let t=new DOMParser,n=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(n.match(/<\/html>/)||n.match(/<\/head>/)||n.match(/<\/body>/)){let o=t.parseFromString(e,"text/html");if(n.match(/<\/html>/))return o.generatedByIdiomorph=!0,o;{let e=o.firstChild;return e?(e.generatedByIdiomorph=!0,e):null}}{let n=t.parseFromString("<body><template>"+e+"</template></body>","text/html").body.querySelector("template").content;return n.generatedByIdiomorph=!0,n}}(o));let r=function(e){if(null==e){return document.createElement("div")}if(e.generatedByIdiomorph)return e;if(e instanceof Node){const t=document.createElement("div");return t.append(e),t}{const t=document.createElement("div");for(const n of[...e])t.append(n);return t}}(o),s=function(e,n,o){return o=function(e){let n={};return Object.assign(n,t),Object.assign(n,e),n.callbacks={},Object.assign(n.callbacks,t.callbacks),Object.assign(n.callbacks,e.callbacks),n.head={},Object.assign(n.head,t.head),Object.assign(n.head,e.head),n}(o),{target:e,newContent:n,config:o,morphStyle:o.morphStyle,ignoreActive:o.ignoreActive,ignoreActiveValue:o.ignoreActiveValue,idMap:w(e,n),deadIds:new Set,callbacks:o.callbacks,head:o.head}}(e,r,i);return n(e,r,s)},defaults:t}}();function A(){if(R.config.loggingEnabled){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];console.log("[hotwire_spark]",...t)}}class w{static async reload(e){const t=await y();return new w(t,e).reload()}constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:/./;this.document=e,this.filePattern=t,this.application=window.Stimulus}async reload(){A("Reload Stimulus controllers..."),this.application.stop(),await this.#e(),this.#t(),this.application.start()}async#e(){await Promise.all(this.#n.map((async e=>this.#o(e))))}get#n(){return this.controllerPathsToReload=this.controllerPathsToReload||this.#i.filter((e=>this.#r(e))),this.controllerPathsToReload}get#i(){return Object.keys(this.#s).filter((e=>e.endsWith("_controller")))}#r(e){return this.filePattern.test(e)}get#s(){return this.pathsByModule=this.pathsByModule||this.#l(),this.pathsByModule}#l(){const e=this.document.querySelector("script[type=importmap]");return JSON.parse(e.text).imports}async#o(e){A(`\t${e}`);const t=this.#c(e),n=v(this.#a(e)),o=await import(n);this.#u(t,o)}#t(){this.#d.forEach((e=>this.#h(e.identifier)))}get#d(){return this.#p?[]:this.application.controllers.filter((e=>this.filePattern.test(`${e.identifier}_controller`)))}get#p(){return this.#n.length>0}#a(e){return this.#s[e]}#c(e){return e.replace(/^.*\//,"").replace("_controller","").replace(/\//g,"--").replace(/_/g,"-")}#u(e,t){this.application.unload(e),this.application.register(e,t.default)}#h(e){A(`\tRemoving controller ${e}`),this.application.unload(e)}}class k{static async reload(){return(new k).reload()}async reload(){const e=await this.#f();await this.#m(e)}async#f(){A("Reload html...");const e=await y();return this.#g(e.body),e}#g(e){S.morph(document.body,e)}async#m(e){return new w(e).reload()}}class C{static async reload(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return new C(...t).reload()}constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:/./;this.filePattern=e}async reload(){A("Reload css..."),await Promise.all(await this.#b())}async#b(){return(await this.#v()).map((e=>this.#y(e)))}async#v(){const e=await y();return Array.from(e.head.querySelectorAll("link[rel='stylesheet']"))}#y(e){return this.#S(e)?this.#A(e):Promise.resolve()}#S(e){return this.filePattern.test(e.getAttribute("href"))}async#A(e){return new Promise((t=>{const n=e.getAttribute("href"),o=this.#w(e)||this.#k(e);o.setAttribute("href",v(e.getAttribute("href"))),o.onload=()=>{A(`\t${n}`),t()}}))}#w(e){return this.#C.find((t=>g(e.href)===g(t.href)))}get#C(){return Array.from(document.querySelectorAll("link[rel='stylesheet']"))}#k(e){return document.head.append(e),e}}m.subscriptions.create({channel:"Hotwire::Spark::Channel"},{connected(){document.body.setAttribute("data-hotwire-spark-ready","")},async received(e){try{await this.dispatch(e)}catch(t){console.log(`Error on ${e.action}`,t)}},dispatch(e){let{action:t,path:n}=e;const o=function(e){return e.split("/").pop().split(".")[0]}(n);switch(t){case"reload_html":return this.reloadHtml();case"reload_css":return this.reloadCss(o);case"reload_stimulus":return this.reloadStimulus(o);default:throw new Error(`Unknown action: ${t}`)}},reloadHtml:()=>k.reload(),reloadCss:e=>C.reload(new RegExp(e)),reloadStimulus:e=>w.reload(new RegExp(e))});const R={config:{loggingEnabled:!1}};return document.addEventListener("DOMContentLoaded",(function(){var e;R.config.loggingEnabled=(e="logging",document.querySelector(`meta[name="hotwire-spark:${e}"]`)?.content)})),R}();
|
1
|
+
var HotwireSpark=function(){"use strict";var e={logger:"undefined"!=typeof console?console:void 0,WebSocket:"undefined"!=typeof WebSocket?WebSocket:void 0},t={log(...t){this.enabled&&(t.push(Date.now()),e.logger.log("[ActionCable]",...t))}};const n=()=>(new Date).getTime(),o=e=>(n()-e)/1e3;class i{constructor(e){this.visibilityDidChange=this.visibilityDidChange.bind(this),this.connection=e,this.reconnectAttempts=0}start(){this.isRunning()||(this.startedAt=n(),delete this.stoppedAt,this.startPolling(),addEventListener("visibilitychange",this.visibilityDidChange),t.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`))}stop(){this.isRunning()&&(this.stoppedAt=n(),this.stopPolling(),removeEventListener("visibilitychange",this.visibilityDidChange),t.log("ConnectionMonitor stopped"))}isRunning(){return this.startedAt&&!this.stoppedAt}recordMessage(){this.pingedAt=n()}recordConnect(){this.reconnectAttempts=0,delete this.disconnectedAt,t.log("ConnectionMonitor recorded connect")}recordDisconnect(){this.disconnectedAt=n(),t.log("ConnectionMonitor recorded disconnect")}startPolling(){this.stopPolling(),this.poll()}stopPolling(){clearTimeout(this.pollTimeout)}poll(){this.pollTimeout=setTimeout((()=>{this.reconnectIfStale(),this.poll()}),this.getPollInterval())}getPollInterval(){const{staleThreshold:e,reconnectionBackoffRate:t}=this.constructor;return 1e3*e*Math.pow(1+t,Math.min(this.reconnectAttempts,10))*(1+(0===this.reconnectAttempts?1:t)*Math.random())}reconnectIfStale(){this.connectionIsStale()&&(t.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${o(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`),this.reconnectAttempts++,this.disconnectedRecently()?t.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${o(this.disconnectedAt)} s`):(t.log("ConnectionMonitor reopening"),this.connection.reopen()))}get refreshedAt(){return this.pingedAt?this.pingedAt:this.startedAt}connectionIsStale(){return o(this.refreshedAt)>this.constructor.staleThreshold}disconnectedRecently(){return this.disconnectedAt&&o(this.disconnectedAt)<this.constructor.staleThreshold}visibilityDidChange(){"visible"===document.visibilityState&&setTimeout((()=>{!this.connectionIsStale()&&this.connection.isOpen()||(t.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`),this.connection.reopen())}),200)}}i.staleThreshold=6,i.reconnectionBackoffRate=.15;var r={message_types:{welcome:"welcome",disconnect:"disconnect",ping:"ping",confirmation:"confirm_subscription",rejection:"reject_subscription"},disconnect_reasons:{unauthorized:"unauthorized",invalid_request:"invalid_request",server_restart:"server_restart",remote:"remote"},default_mount_path:"/cable",protocols:["actioncable-v1-json","actioncable-unsupported"]};const{message_types:s,protocols:c}=r,l=c.slice(0,c.length-1),a=[].indexOf;class d{constructor(e){this.open=this.open.bind(this),this.consumer=e,this.subscriptions=this.consumer.subscriptions,this.monitor=new i(this),this.disconnected=!0}send(e){return!!this.isOpen()&&(this.webSocket.send(JSON.stringify(e)),!0)}open(){if(this.isActive())return t.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`),!1;{const n=[...c,...this.consumer.subprotocols||[]];return t.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${n}`),this.webSocket&&this.uninstallEventHandlers(),this.webSocket=new e.WebSocket(this.consumer.url,n),this.installEventHandlers(),this.monitor.start(),!0}}close({allowReconnect:e}={allowReconnect:!0}){if(e||this.monitor.stop(),this.isOpen())return this.webSocket.close()}reopen(){if(t.log(`Reopening WebSocket, current state is ${this.getState()}`),!this.isActive())return this.open();try{return this.close()}catch(e){t.log("Failed to reopen WebSocket",e)}finally{t.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`),setTimeout(this.open,this.constructor.reopenDelay)}}getProtocol(){if(this.webSocket)return this.webSocket.protocol}isOpen(){return this.isState("open")}isActive(){return this.isState("open","connecting")}triedToReconnect(){return this.monitor.reconnectAttempts>0}isProtocolSupported(){return a.call(l,this.getProtocol())>=0}isState(...e){return a.call(e,this.getState())>=0}getState(){if(this.webSocket)for(let t in e.WebSocket)if(e.WebSocket[t]===this.webSocket.readyState)return t.toLowerCase();return null}installEventHandlers(){for(let e in this.events){const t=this.events[e].bind(this);this.webSocket[`on${e}`]=t}}uninstallEventHandlers(){for(let e in this.events)this.webSocket[`on${e}`]=function(){}}}d.reopenDelay=500,d.prototype.events={message(e){if(!this.isProtocolSupported())return;const{identifier:n,message:o,reason:i,reconnect:r,type:c}=JSON.parse(e.data);switch(this.monitor.recordMessage(),c){case s.welcome:return this.triedToReconnect()&&(this.reconnectAttempted=!0),this.monitor.recordConnect(),this.subscriptions.reload();case s.disconnect:return t.log(`Disconnecting. Reason: ${i}`),this.close({allowReconnect:r});case s.ping:return null;case s.confirmation:return this.subscriptions.confirmSubscription(n),this.reconnectAttempted?(this.reconnectAttempted=!1,this.subscriptions.notify(n,"connected",{reconnected:!0})):this.subscriptions.notify(n,"connected",{reconnected:!1});case s.rejection:return this.subscriptions.reject(n);default:return this.subscriptions.notify(n,"received",o)}},open(){if(t.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`),this.disconnected=!1,!this.isProtocolSupported())return t.log("Protocol is unsupported. Stopping monitor and disconnecting."),this.close({allowReconnect:!1})},close(e){if(t.log("WebSocket onclose event"),!this.disconnected)return this.disconnected=!0,this.monitor.recordDisconnect(),this.subscriptions.notifyAll("disconnected",{willAttemptReconnect:this.monitor.isRunning()})},error(){t.log("WebSocket onerror event")}};class u{constructor(e,t={},n){this.consumer=e,this.identifier=JSON.stringify(t),function(e,t){if(null!=t)for(let n in t){const o=t[n];e[n]=o}}(this,n)}perform(e,t={}){return t.action=e,this.send(t)}send(e){return this.consumer.send({command:"message",identifier:this.identifier,data:JSON.stringify(e)})}unsubscribe(){return this.consumer.subscriptions.remove(this)}}class h{constructor(e){this.subscriptions=e,this.pendingSubscriptions=[]}guarantee(e){-1==this.pendingSubscriptions.indexOf(e)?(t.log(`SubscriptionGuarantor guaranteeing ${e.identifier}`),this.pendingSubscriptions.push(e)):t.log(`SubscriptionGuarantor already guaranteeing ${e.identifier}`),this.startGuaranteeing()}forget(e){t.log(`SubscriptionGuarantor forgetting ${e.identifier}`),this.pendingSubscriptions=this.pendingSubscriptions.filter((t=>t!==e))}startGuaranteeing(){this.stopGuaranteeing(),this.retrySubscribing()}stopGuaranteeing(){clearTimeout(this.retryTimeout)}retrySubscribing(){this.retryTimeout=setTimeout((()=>{this.subscriptions&&"function"==typeof this.subscriptions.subscribe&&this.pendingSubscriptions.map((e=>{t.log(`SubscriptionGuarantor resubscribing ${e.identifier}`),this.subscriptions.subscribe(e)}))}),500)}}class p{constructor(e){this.consumer=e,this.guarantor=new h(this),this.subscriptions=[]}create(e,t){const n="object"==typeof e?e:{channel:e},o=new u(this.consumer,n,t);return this.add(o)}add(e){return this.subscriptions.push(e),this.consumer.ensureActiveConnection(),this.notify(e,"initialized"),this.subscribe(e),e}remove(e){return this.forget(e),this.findAll(e.identifier).length||this.sendCommand(e,"unsubscribe"),e}reject(e){return this.findAll(e).map((e=>(this.forget(e),this.notify(e,"rejected"),e)))}forget(e){return this.guarantor.forget(e),this.subscriptions=this.subscriptions.filter((t=>t!==e)),e}findAll(e){return this.subscriptions.filter((t=>t.identifier===e))}reload(){return this.subscriptions.map((e=>this.subscribe(e)))}notifyAll(e,...t){return this.subscriptions.map((n=>this.notify(n,e,...t)))}notify(e,t,...n){let o;return o="string"==typeof e?this.findAll(e):[e],o.map((e=>"function"==typeof e[t]?e[t](...n):void 0))}subscribe(e){this.sendCommand(e,"subscribe")&&this.guarantor.guarantee(e)}confirmSubscription(e){t.log(`Subscription confirmed ${e}`),this.findAll(e).map((e=>this.guarantor.forget(e)))}sendCommand(e,t){const{identifier:n}=e;return this.consumer.send({command:t,identifier:n})}}class f{constructor(e){this._url=e,this.subscriptions=new p(this),this.connection=new d(this),this.subprotocols=[]}get url(){return function(e){"function"==typeof e&&(e=e());if(e&&!/^wss?:/i.test(e)){const t=document.createElement("a");return t.href=e,t.href=t.href,t.protocol=t.protocol.replace("http","ws"),t.href}return e}(this._url)}send(e){return this.connection.send(e)}connect(){return this.connection.open()}disconnect(){return this.connection.close({allowReconnect:!1})}ensureActiveConnection(){if(!this.connection.isActive())return this.connection.open()}addSubProtocol(e){this.subprotocols=[...this.subprotocols,e]}}var m=function(e=function(e){const t=document.head.querySelector(`meta[name='action-cable-${e}']`);if(t)return t.getAttribute("content")}("url")||r.default_mount_path){return new f(e)}("/hotwire-spark");function g(e){return e.replace(/-[a-z0-9]+\.(\w+)(\?.*)?$/,".$1")}function b(e,t){const n=new URL(e,window.location.origin);return Object.entries(t).forEach((e=>{let[t,o]=e;n.searchParams.set(t,o)})),n.toString()}function v(e){return b(e,{reload:Date.now()})}async function S(){let e=v(b(window.location.href,{hotwire_spark:"true"}));const t=await fetch(e,{headers:{Accept:"text/html"}});if(!t.ok)throw new Error(`${t.status} when fetching ${e}`);const n=await t.text();return(new DOMParser).parseFromString(n,"text/html")}var y=function(){let e=new Set,t={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:a,afterNodeAdded:a,beforeNodeMorphed:a,afterNodeMorphed:a,beforeNodeRemoved:a,afterNodeRemoved:a,beforeAttributeUpdated:a},head:{style:"merge",shouldPreserve:function(e){return"true"===e.getAttribute("im-preserve")},shouldReAppend:function(e){return"true"===e.getAttribute("im-re-append")},shouldRemove:a,afterHeadMorphed:a}};function n(e,t,o){if(o.head.block){let i=e.querySelector("head"),r=t.querySelector("head");if(i&&r){let s=l(r,i,o);return void Promise.all(s).then((function(){n(e,t,Object.assign(o,{head:{block:!1,ignore:!0}}))}))}}if("innerHTML"===o.morphStyle)return r(t,e,o),e.children;if("outerHTML"===o.morphStyle||null==o.morphStyle){let n=function(e,t,n){let o;o=e.firstChild;let i=o,r=0;for(;o;){let e=m(o,t,n);e>r&&(i=o,r=e),o=o.nextSibling}return i}(t,e,o),r=n?.previousSibling,s=n?.nextSibling,c=i(e,n,o);return n?function(e,t,n){let o=[],i=[];for(;null!=e;)o.push(e),e=e.previousSibling;for(;o.length>0;){let e=o.pop();i.push(e),t.parentElement.insertBefore(e,t)}i.push(t);for(;null!=n;)o.push(n),i.push(n),n=n.nextSibling;for(;o.length>0;)t.parentElement.insertBefore(o.pop(),t.nextSibling);return i}(r,c,s):[]}throw"Do not understand how to morph style "+o.morphStyle}function o(e,t){return t.ignoreActiveValue&&e===document.activeElement}function i(e,t,n){if(!n.ignoreActive||e!==document.activeElement)return null==t?!1===n.callbacks.beforeNodeRemoved(e)?e:(e.remove(),n.callbacks.afterNodeRemoved(e),null):u(e,t)?(!1===n.callbacks.beforeNodeMorphed(e,t)||(e instanceof HTMLHeadElement&&n.head.ignore||(e instanceof HTMLHeadElement&&"morph"!==n.head.style?l(t,e,n):(!function(e,t,n){let i=e.nodeType;if(1===i){const o=e.attributes,i=t.attributes;for(const e of o)s(e.name,t,"update",n)||t.getAttribute(e.name)!==e.value&&t.setAttribute(e.name,e.value);for(let o=i.length-1;0<=o;o--){const r=i[o];s(r.name,t,"remove",n)||(e.hasAttribute(r.name)||t.removeAttribute(r.name))}}8!==i&&3!==i||t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue);o(t,n)||function(e,t,n){if(e instanceof HTMLInputElement&&t instanceof HTMLInputElement&&"file"!==e.type){let o=e.value,i=t.value;c(e,t,"checked",n),c(e,t,"disabled",n),e.hasAttribute("value")?o!==i&&(s("value",t,"update",n)||(t.setAttribute("value",o),t.value=o)):s("value",t,"remove",n)||(t.value="",t.removeAttribute("value"))}else if(e instanceof HTMLOptionElement)c(e,t,"selected",n);else if(e instanceof HTMLTextAreaElement&&t instanceof HTMLTextAreaElement){let o=e.value,i=t.value;if(s("value",t,"update",n))return;o!==i&&(t.value=o),t.firstChild&&t.firstChild.nodeValue!==o&&(t.firstChild.nodeValue=o)}}(e,t,n)}(t,e,n),o(e,n)||r(t,e,n))),n.callbacks.afterNodeMorphed(e,t)),e):!1===n.callbacks.beforeNodeRemoved(e)||!1===n.callbacks.beforeNodeAdded(t)?e:(e.parentElement.replaceChild(t,e),n.callbacks.afterNodeAdded(t),n.callbacks.afterNodeRemoved(e),t)}function r(e,t,n){let o,r=e.firstChild,s=t.firstChild;for(;r;){if(o=r,r=o.nextSibling,null==s){if(!1===n.callbacks.beforeNodeAdded(o))return;t.appendChild(o),n.callbacks.afterNodeAdded(o),S(n,o);continue}if(d(o,s,n)){i(s,o,n),s=s.nextSibling,S(n,o);continue}let c=p(e,t,o,s,n);if(c){s=h(s,c,n),i(c,o,n),S(n,o);continue}let l=f(e,t,o,s,n);if(l)s=h(s,l,n),i(l,o,n),S(n,o);else{if(!1===n.callbacks.beforeNodeAdded(o))return;t.insertBefore(o,s),n.callbacks.afterNodeAdded(o),S(n,o)}}for(;null!==s;){let e=s;s=s.nextSibling,g(e,n)}}function s(e,t,n,o){return!("value"!==e||!o.ignoreActiveValue||t!==document.activeElement)||!1===o.callbacks.beforeAttributeUpdated(e,t,n)}function c(e,t,n,o){if(e[n]!==t[n]){let i=s(n,t,"update",o);i||(t[n]=e[n]),e[n]?i||t.setAttribute(n,e[n]):s(n,t,"remove",o)||t.removeAttribute(n)}}function l(e,t,n){let o=[],i=[],r=[],s=[],c=n.head.style,l=new Map;for(const t of e.children)l.set(t.outerHTML,t);for(const e of t.children){let t=l.has(e.outerHTML),o=n.head.shouldReAppend(e),a=n.head.shouldPreserve(e);t||a?o?i.push(e):(l.delete(e.outerHTML),r.push(e)):"append"===c?o&&(i.push(e),s.push(e)):!1!==n.head.shouldRemove(e)&&i.push(e)}s.push(...l.values());let a=[];for(const e of s){let i=document.createRange().createContextualFragment(e.outerHTML).firstChild;if(!1!==n.callbacks.beforeNodeAdded(i)){if(i.href||i.src){let e=null,t=new Promise((function(t){e=t}));i.addEventListener("load",(function(){e()})),a.push(t)}t.appendChild(i),n.callbacks.afterNodeAdded(i),o.push(i)}}for(const e of i)!1!==n.callbacks.beforeNodeRemoved(e)&&(t.removeChild(e),n.callbacks.afterNodeRemoved(e));return n.head.afterHeadMorphed(t,{added:o,kept:r,removed:i}),a}function a(){}function d(e,t,n){return null!=e&&null!=t&&(e.nodeType===t.nodeType&&e.tagName===t.tagName&&(""!==e.id&&e.id===t.id||y(n,e,t)>0))}function u(e,t){return null!=e&&null!=t&&(e.nodeType===t.nodeType&&e.tagName===t.tagName)}function h(e,t,n){for(;e!==t;){let t=e;e=e.nextSibling,g(t,n)}return S(n,t),t.nextSibling}function p(e,t,n,o,i){let r=y(i,n,t);if(r>0){let t=o,s=0;for(;null!=t;){if(d(n,t,i))return t;if(s+=y(i,t,e),s>r)return null;t=t.nextSibling}}return null}function f(e,t,n,o,i){let r=o,s=n.nextSibling,c=0;for(;null!=r;){if(y(i,r,e)>0)return null;if(u(n,r))return r;if(u(s,r)&&(c++,s=s.nextSibling,c>=2))return null;r=r.nextSibling}return r}function m(e,t,n){return u(e,t)?.5+y(n,e,t):0}function g(e,t){S(t,e),!1!==t.callbacks.beforeNodeRemoved(e)&&(e.remove(),t.callbacks.afterNodeRemoved(e))}function b(e,t){return!e.deadIds.has(t)}function v(t,n,o){return(t.idMap.get(o)||e).has(n)}function S(t,n){let o=t.idMap.get(n)||e;for(const e of o)t.deadIds.add(e)}function y(t,n,o){let i=t.idMap.get(n)||e,r=0;for(const e of i)b(t,e)&&v(t,e,o)&&++r;return r}function w(e,t){let n=e.parentElement,o=e.querySelectorAll("[id]");for(const e of o){let o=e;for(;o!==n&&null!=o;){let n=t.get(o);null==n&&(n=new Set,t.set(o,n)),n.add(e.id),o=o.parentElement}}}function A(e,t){let n=new Map;return w(e,n),w(t,n),n}return{morph:function(e,o,i={}){e instanceof Document&&(e=e.documentElement),"string"==typeof o&&(o=function(e){let t=new DOMParser,n=e.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(n.match(/<\/html>/)||n.match(/<\/head>/)||n.match(/<\/body>/)){let o=t.parseFromString(e,"text/html");if(n.match(/<\/html>/))return o.generatedByIdiomorph=!0,o;{let e=o.firstChild;return e?(e.generatedByIdiomorph=!0,e):null}}{let n=t.parseFromString("<body><template>"+e+"</template></body>","text/html").body.querySelector("template").content;return n.generatedByIdiomorph=!0,n}}(o));let r=function(e){if(null==e){return document.createElement("div")}if(e.generatedByIdiomorph)return e;if(e instanceof Node){const t=document.createElement("div");return t.append(e),t}{const t=document.createElement("div");for(const n of[...e])t.append(n);return t}}(o),s=function(e,n,o){return o=function(e){let n={};return Object.assign(n,t),Object.assign(n,e),n.callbacks={},Object.assign(n.callbacks,t.callbacks),Object.assign(n.callbacks,e.callbacks),n.head={},Object.assign(n.head,t.head),Object.assign(n.head,e.head),n}(o),{target:e,newContent:n,config:o,morphStyle:o.morphStyle,ignoreActive:o.ignoreActive,ignoreActiveValue:o.ignoreActiveValue,idMap:A(e,n),deadIds:new Set,callbacks:o.callbacks,head:o.head}}(e,r,i);return n(e,r,s)},defaults:t}}();function w(){if(E.config.loggingEnabled){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];console.log("[hotwire_spark]",...t)}}class A{static async reload(e){return new A(e).reload()}static async reloadAll(){return Stimulus.controllers.forEach((e=>{Stimulus.unload(e.identifier),Stimulus.register(e.identifier,e.constructor)})),Promise.resolve()}constructor(e){this.changedPath=e,this.application=window.Stimulus}async reload(){w("Reload Stimulus controllers..."),this.application.stop();try{await this.#e()}catch(e){e instanceof k?this.#t():console.error("Error reloading controller",e)}this.application.start()}async#e(){const e=await this.#n(this.changedPath);await this.#o(this.#i,e)}async#n(e){const t=await fetch(`/spark/source_files/?path=${e}`);if(404===t.status)throw new k(`Source file not found: ${e}`);const n=await t.text(),o=new Blob([n],{type:"application/javascript"}),i=URL.createObjectURL(o),r=await import(i);return URL.revokeObjectURL(i),r}get#i(){return this.changedControllerIdentifier=this.changedControllerIdentifier||this.#r(this.changedPath),this.changedControllerIdentifier}#r(e){return e.replace(/^.*\//,"").replace("_controller","").replace(/\//g,"--").replace(/_/g,"-").replace(/\.js$/,"")}#t(){this.#s(this.#i)}#o(e,t){w("\tReloading controller",e),this.application.unload(e),this.application.register(e,t.default)}#s(e){w(`\tRemoving controller ${e}`),this.application.unload(e)}}class k extends Error{}class C{static async reload(){return(new C).reload()}async reload(){await this.#c(),await this.#l()}async#c(){w("Reload html with morph...");const e=await S();return this.#a(e.body),e}#a(e){y.morph(document.body,e)}async#l(){await A.reloadAll()}}class R{static async reload(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return new R(...t).reload()}constructor(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:/./;this.filePattern=e}async reload(){w("Reload css..."),await Promise.all(await this.#d())}async#d(){return(await this.#u()).map((e=>this.#h(e)))}async#u(){const e=await S();return Array.from(e.head.querySelectorAll("link[rel='stylesheet']"))}#h(e){return this.#p(e)?this.#f(e):Promise.resolve()}#p(e){return this.filePattern.test(e.getAttribute("href"))}async#f(e){return new Promise((t=>{const n=e.getAttribute("href"),o=this.#m(e)||this.#g(e);o.setAttribute("href",v(e.getAttribute("href"))),o.onload=()=>{w(`\t${n}`),t()}}))}#m(e){return this.#b.find((t=>g(e.href)===g(t.href)))}get#b(){return Array.from(document.querySelectorAll("link[rel='stylesheet']"))}#g(e){return document.head.append(e),e}}class M{static async reload(){return(new M).reload()}async reload(){await this.#c()}async#c(){w("Reload html with Turbo..."),this.#v(),await this.#S()}#v(){document.addEventListener("turbo:before-render",(()=>{Turbo.navigator.currentVisit.scrolled=!0}),{once:!0})}#S(){return new Promise((e=>{document.addEventListener("turbo:load",(()=>e(document)),{once:!0}),window.Turbo.visit(window.location)}))}}m.subscriptions.create({channel:"Hotwire::Spark::Channel"},{connected(){document.body.setAttribute("data-hotwire-spark-ready","")},async received(e){try{await this.dispatch(e)}catch(t){console.log(`Error on ${e.action}`,t)}},dispatch(e){let{action:t,path:n}=e;switch(t){case"reload_html":return this.reloadHtml();case"reload_css":return this.reloadCss(n);case"reload_stimulus":return this.reloadStimulus(n);default:throw new Error(`Unknown action: ${t}`)}},reloadHtml:()=>("morph"==HotwireSpark.config.htmlReloadMethod?C:M).reload(),reloadCss(e){const t=function(e){return e.split("/").pop().split(".")[0]}(e);return R.reload(new RegExp(t))},reloadStimulus:e=>A.reload(e)});const E={config:{loggingEnabled:!1,htmlReloadMethod:"morph"}},L={loggingEnabled:"logging",htmlReloadMethod:"html-reload-method"};return document.addEventListener("DOMContentLoaded",(function(){Object.entries(L).forEach((e=>{let[t,n]=e;var o;E.config[t]=(o=n,document.querySelector(`meta[name="hotwire-spark:${o}"]`)?.content)}))})),E}();
|
2
2
|
//# sourceMappingURL=hotwire_spark.min.js.map
|