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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04d3314e939e32bc7f34e2d83cf3f09d03ed20aa5628974783882667a639e78b
4
- data.tar.gz: 5d379a4109419edb48274cecebd6e920eca4ae010ca69c9d4f1927d9b934ba54
3
+ metadata.gz: 86280ef674a47bc00119c73166435a363c34e6c22804444df25d8f909fe5755c
4
+ data.tar.gz: 016b6bc8f6bf0f22bf3cec4baa754a167fdc526230f0a57df83c1f0916ee4f56
5
5
  SHA512:
6
- metadata.gz: f6f6f40a7c2e0fa8c5820681787800734a584047d83b59905c7203a318a7293b6819470995da0bc68e9e3712930569d4268285e940384914b1b81b62ff10a2cc
7
- data.tar.gz: 836c7825604bb9c77ab87550ec29cbcf80e1289d0968f12eab0c19ee30ec2d3e56f59814e9a99689b52f6040fe6b09c9f11d4d48f567e84c05e6d4ec41f2cc91
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
- * **HTML change:** it fetches the new document body and updates the current body with morphing. It uses [`idiomorph`](https://github.com/bigskysoftware/idiomorph) under the hood.
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
- > [!NOTE]
32
- > Hotwire Spark currently does not support `jsbundling`, only import maps.
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 | Description |
43
- |------------------|------------------------------------------------------------------------------------------------------------------------------|
44
- | `html_paths` | Paths where file changes trigger a content refresh. By default: `app/controllers`, `app/helpers`, `app/models`, `app/views`. |
45
- | `css_paths` | Paths where file changes trigger a CSS refresh. By default: `app/assets/stylesheets` or `app/assets/builds` if exists. |
46
- | `stimulus_paths` | Paths where file changes trigger a Stimulus controller refresh. By default: `app/javascript/controllers`. |
47
- | `enabled` | Enable or disable live reloading. By default, it's only enabled in `development`. |
48
- | `logging` | Show logs in the browser console when reloading happens. It's false by default. |
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(filePattern) {
1400
- const document = await reloadHtmlDocument();
1401
- return new StimulusReloader(document, filePattern).reload();
1399
+ static async reload(path) {
1400
+ return new StimulusReloader(path).reload();
1402
1401
  }
1403
- constructor(document) {
1404
- let filePattern = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : /./;
1405
- this.document = document;
1406
- this.filePattern = filePattern;
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
- await this.#reloadChangedStimulusControllers();
1413
- this.#unloadDeletedStimulusControllers();
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 #reloadChangedStimulusControllers() {
1417
- await Promise.all(this.#stimulusControllerPathsToReload.map(async moduleName => this.#reloadStimulusController(moduleName)));
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
- get #stimulusControllerPaths() {
1424
- return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith("_controller"));
1425
- }
1426
- #shouldReloadController(path) {
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 #didChangeTriggerAReload() {
1455
- return this.#stimulusControllerPathsToReload.length > 0;
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 HtmlReloader {
1467
+ class MorphHtmlReloader {
1474
1468
  static async reload() {
1475
- return new HtmlReloader().reload();
1469
+ return new MorphHtmlReloader().reload();
1476
1470
  }
1477
1471
  async reload() {
1478
- const reloadedDocument = await this.#reloadHtml();
1479
- await this.#reloadStimulus(reloadedDocument);
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(reloadedDocument) {
1491
- return new StimulusReloader(reloadedDocument).reload();
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(fileName);
1596
+ return this.reloadCss(path);
1575
1597
  case "reload_stimulus":
1576
- return this.reloadStimulus(fileName);
1598
+ return this.reloadStimulus(path);
1577
1599
  default:
1578
1600
  throw new Error(`Unknown action: ${action}`);
1579
1601
  }
1580
1602
  },
1581
1603
  reloadHtml() {
1582
- return HtmlReloader.reload();
1604
+ const htmlReloader = HotwireSpark.config.htmlReloadMethod == "morph" ? MorphHtmlReloader : ReplaceHtmlReloader;
1605
+ return htmlReloader.reload();
1583
1606
  },
1584
- reloadCss(fileName) {
1607
+ reloadCss(path) {
1608
+ const fileName = assetNameFromPath(path);
1585
1609
  return CssReloader.reload(new RegExp(fileName));
1586
1610
  },
1587
- reloadStimulus(fileName) {
1588
- return StimulusReloader.reload(new RegExp(fileName));
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
- HotwireSpark.config.loggingEnabled = getConfigurationProperty("logging");
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