hotwire-spark 0.1.10 → 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -11
- data/app/assets/javascripts/hotwire_spark.js +54 -38
- data/app/assets/javascripts/hotwire_spark.min.js +1 -1
- data/app/assets/javascripts/hotwire_spark.min.js.map +1 -1
- data/app/javascript/hotwire/spark/reloaders/replace_html_reloader.js +2 -2
- data/app/javascript/hotwire/spark/reloaders/stimulus_reloader.js +66 -40
- data/lib/hotwire/spark/change.rb +37 -0
- data/lib/hotwire/spark/installer.rb +1 -17
- data/lib/hotwire/spark/version.rb +1 -1
- metadata +3 -3
- data/app/controllers/hotwire/spark/source_files_controller.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a60c3dbc696c19fcf78bd3812bf58af629f7dfefa67d6274245453fefbbdbf4a
|
4
|
+
data.tar.gz: a14f7ad1b6d4071e3b2e274597a069a34a90e59b2ff7e4eaeb1ddbb3ede86994
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 869ea5cbfe198c1a9f88bd11c1941ac5b2f55941b2d702ca60c8f921ade65923dba230fbe0e9b6e5b9f0ff5fb6f76aaad66785aaa975756399d661089c895bcf
|
7
|
+
data.tar.gz: 2063ea1ede77efcf9747c1b31615c613f9a8ae633d1bec48b76e00a269ef148201a6888e97083b8356adb36fa9877d0e2dc873771835e167b3ae1dce5609d4ec
|
data/README.md
CHANGED
@@ -52,17 +52,24 @@ You can set configuration options on your `development.rb`. For example:
|
|
52
52
|
config.hotwire.spark.html_paths += %w[ lib ]
|
53
53
|
```
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
|
58
|
-
|
59
|
-
| `
|
60
|
-
| `
|
61
|
-
| `
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
|
55
|
+
### General
|
56
|
+
|
57
|
+
| Name | Description |
|
58
|
+
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
59
|
+
| `enabled` | Enable or disable live reloading. By default, it's only enabled in `development`. |
|
60
|
+
| `logging` | Show logs in the browser console when reloading happens. It's false by default. |
|
61
|
+
| `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>` and keep the scroll. |
|
62
|
+
|
63
|
+
### Monitored paths
|
64
|
+
|
65
|
+
| Name | Description |
|
66
|
+
|-----------------------|------------------------------------------------------------------------------------------------------------------------------|
|
67
|
+
| `html_paths` | Paths where file changes trigger a content refresh. By default: `app/controllers`, `app/helpers`, `app/models`, `app/views`. |
|
68
|
+
| `html_extensions` | The extensions to monitor for HTML content changes. By default: `rb`, `erb`. | |
|
69
|
+
| `css_paths` | Paths where file changes trigger a CSS refresh. By default: `app/assets/stylesheets` or `app/assets/builds` if exists. |
|
70
|
+
| `css_extensions` | The extensions to monitor for CSS changes. By default: `css`. | |
|
71
|
+
| `stimulus_paths` | Paths where file changes trigger a Stimulus controller refresh. By default: `app/javascript/controllers`. |
|
72
|
+
| `stimulus_extensions` | The extensions to monitor for Stimulus changes. By default: `js`. | |
|
66
73
|
|
67
74
|
## License
|
68
75
|
|
@@ -1396,8 +1396,9 @@ var HotwireSpark = (function () {
|
|
1396
1396
|
}
|
1397
1397
|
|
1398
1398
|
class StimulusReloader {
|
1399
|
-
static async reload(
|
1400
|
-
|
1399
|
+
static async reload(changedFilePath) {
|
1400
|
+
const document = await reloadHtmlDocument();
|
1401
|
+
return new StimulusReloader(document, changedFilePath).reload();
|
1401
1402
|
}
|
1402
1403
|
static async reloadAll() {
|
1403
1404
|
Stimulus.controllers.forEach(controller => {
|
@@ -1406,54 +1407,70 @@ var HotwireSpark = (function () {
|
|
1406
1407
|
});
|
1407
1408
|
return Promise.resolve();
|
1408
1409
|
}
|
1409
|
-
constructor(
|
1410
|
-
this.
|
1410
|
+
constructor(document, changedFilePath) {
|
1411
|
+
this.document = document;
|
1412
|
+
this.changedFilePath = changedFilePath;
|
1411
1413
|
this.application = window.Stimulus;
|
1412
1414
|
}
|
1413
1415
|
async reload() {
|
1414
1416
|
log("Reload Stimulus controllers...");
|
1415
1417
|
this.application.stop();
|
1416
|
-
|
1417
|
-
|
1418
|
-
} catch (error) {
|
1419
|
-
if (error instanceof SourceFileNotFound) {
|
1420
|
-
this.#deregisterChangedController();
|
1421
|
-
} else {
|
1422
|
-
console.error("Error reloading controller", error);
|
1423
|
-
}
|
1424
|
-
}
|
1418
|
+
await this.#reloadChangedStimulusControllers();
|
1419
|
+
this.#unloadDeletedStimulusControllers();
|
1425
1420
|
this.application.start();
|
1426
1421
|
}
|
1427
|
-
async #
|
1428
|
-
|
1429
|
-
await this.#registerController(this.#changedControllerIdentifier, module);
|
1422
|
+
async #reloadChangedStimulusControllers() {
|
1423
|
+
await Promise.all(this.#stimulusControllerPathsToReload.map(async moduleName => this.#reloadStimulusController(moduleName)));
|
1430
1424
|
}
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
const moduleUrl = URL.createObjectURL(blob);
|
1441
|
-
const module = await import(moduleUrl);
|
1442
|
-
URL.revokeObjectURL(moduleUrl);
|
1443
|
-
return module;
|
1425
|
+
get #stimulusControllerPathsToReload() {
|
1426
|
+
this.controllerPathsToReload = this.controllerPathsToReload || this.#stimulusControllerPaths.filter(path => this.#shouldReloadController(path));
|
1427
|
+
return this.controllerPathsToReload;
|
1428
|
+
}
|
1429
|
+
get #stimulusControllerPaths() {
|
1430
|
+
return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith("_controller"));
|
1431
|
+
}
|
1432
|
+
#shouldReloadController(path) {
|
1433
|
+
return this.#extractControllerName(path) === this.#changedControllerIdentifier;
|
1444
1434
|
}
|
1445
1435
|
get #changedControllerIdentifier() {
|
1446
|
-
this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.
|
1436
|
+
this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.changedFilePath);
|
1447
1437
|
return this.changedControllerIdentifier;
|
1448
1438
|
}
|
1449
|
-
#
|
1450
|
-
|
1439
|
+
get #stimulusPathsByModule() {
|
1440
|
+
this.pathsByModule = this.pathsByModule || this.#parseImportmapJson();
|
1441
|
+
return this.pathsByModule;
|
1451
1442
|
}
|
1452
|
-
#
|
1453
|
-
this
|
1443
|
+
#parseImportmapJson() {
|
1444
|
+
const importmapScript = this.document.querySelector("script[type=importmap]");
|
1445
|
+
return JSON.parse(importmapScript.text).imports;
|
1446
|
+
}
|
1447
|
+
async #reloadStimulusController(moduleName) {
|
1448
|
+
log(`\t${moduleName}`);
|
1449
|
+
const controllerName = this.#extractControllerName(moduleName);
|
1450
|
+
const path = cacheBustedUrl(this.#pathForModuleName(moduleName));
|
1451
|
+
const module = await import(path);
|
1452
|
+
this.#registerController(controllerName, module);
|
1453
|
+
}
|
1454
|
+
#unloadDeletedStimulusControllers() {
|
1455
|
+
this.#controllersToUnload.forEach(controller => this.#deregisterController(controller.identifier));
|
1456
|
+
}
|
1457
|
+
get #controllersToUnload() {
|
1458
|
+
if (this.#didChangeTriggerAReload) {
|
1459
|
+
return [];
|
1460
|
+
} else {
|
1461
|
+
return this.application.controllers.filter(controller => this.#changedControllerIdentifier === controller.identifier);
|
1462
|
+
}
|
1463
|
+
}
|
1464
|
+
get #didChangeTriggerAReload() {
|
1465
|
+
return this.#stimulusControllerPathsToReload.length > 0;
|
1466
|
+
}
|
1467
|
+
#pathForModuleName(moduleName) {
|
1468
|
+
return this.#stimulusPathsByModule[moduleName];
|
1469
|
+
}
|
1470
|
+
#extractControllerName(path) {
|
1471
|
+
return path.replace(/^\/+/, "").replace(/^controllers\//, "").replace("_controller", "").replace(/\//g, "--").replace(/_/g, "-").replace(/\.js$/, "");
|
1454
1472
|
}
|
1455
1473
|
#registerController(name, module) {
|
1456
|
-
log("\tReloading controller", name);
|
1457
1474
|
this.application.unload(name);
|
1458
1475
|
this.application.register(name, module.default);
|
1459
1476
|
}
|
@@ -1462,7 +1479,6 @@ var HotwireSpark = (function () {
|
|
1462
1479
|
this.application.unload(name);
|
1463
1480
|
}
|
1464
1481
|
}
|
1465
|
-
class SourceFileNotFound extends Error {}
|
1466
1482
|
|
1467
1483
|
class MorphHtmlReloader {
|
1468
1484
|
static async reload() {
|
@@ -1551,10 +1567,10 @@ var HotwireSpark = (function () {
|
|
1551
1567
|
}
|
1552
1568
|
async #reloadHtml() {
|
1553
1569
|
log("Reload html with Turbo...");
|
1554
|
-
this.#
|
1570
|
+
this.#keepScrollPosition();
|
1555
1571
|
await this.#visitCurrentPage();
|
1556
1572
|
}
|
1557
|
-
#
|
1573
|
+
#keepScrollPosition() {
|
1558
1574
|
document.addEventListener("turbo:before-render", () => {
|
1559
1575
|
Turbo.navigator.currentVisit.scrolled = true;
|
1560
1576
|
}, {
|
@@ -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: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}();
|
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 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=[...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(){}}}d.reopenDelay=500,d.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 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=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):u(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),S(n,o);continue}if(d(o,s,n)){i(s,o,n),s=s.nextSibling,S(n,o);continue}let l=p(e,t,o,s,n);if(l){s=h(s,l,n),i(l,o,n),S(n,o);continue}let c=f(e,t,o,s,n);if(c)s=h(s,c,n),i(c,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 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 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,l=0;for(;null!=r;){if(y(i,r,e)>0)return null;if(u(n,r))return r;if(u(s,r)&&(l++,s=s.nextSibling,l>=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(M.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){const t=await S();return new A(t,e).reload()}static async reloadAll(){return Stimulus.controllers.forEach((e=>{Stimulus.unload(e.identifier),Stimulus.register(e.identifier,e.constructor)})),Promise.resolve()}constructor(e,t){this.document=e,this.changedFilePath=t,this.application=window.Stimulus}async reload(){w("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.#l(e)===this.#c}get#c(){return this.changedControllerIdentifier=this.changedControllerIdentifier||this.#l(this.changedFilePath),this.changedControllerIdentifier}get#s(){return this.pathsByModule=this.pathsByModule||this.#a(),this.pathsByModule}#a(){const e=this.document.querySelector("script[type=importmap]");return JSON.parse(e.text).imports}async#o(e){w(`\t${e}`);const t=this.#l(e),n=v(this.#d(e)),o=await import(n);this.#u(t,o)}#t(){this.#h.forEach((e=>this.#p(e.identifier)))}get#h(){return this.#f?[]:this.application.controllers.filter((e=>this.#c===e.identifier))}get#f(){return this.#n.length>0}#d(e){return this.#s[e]}#l(e){return e.replace(/^\/+/,"").replace(/^controllers\//,"").replace("_controller","").replace(/\//g,"--").replace(/_/g,"-").replace(/\.js$/,"")}#u(e,t){this.application.unload(e),this.application.register(e,t.default)}#p(e){w(`\tRemoving controller ${e}`),this.application.unload(e)}}class k{static async reload(){return(new k).reload()}async reload(){await this.#m(),await this.#g()}async#m(){w("Reload html with morph...");const e=await S();return this.#b(e.body),e}#b(e){y.morph(document.body,e)}async#g(){await A.reloadAll()}}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(){w("Reload css..."),await Promise.all(await this.#v())}async#v(){return(await this.#S()).map((e=>this.#y(e)))}async#S(){const e=await S();return Array.from(e.head.querySelectorAll("link[rel='stylesheet']"))}#y(e){return this.#w(e)?this.#A(e):Promise.resolve()}#w(e){return this.filePattern.test(e.getAttribute("href"))}async#A(e){return new Promise((t=>{const n=e.getAttribute("href"),o=this.#k(e)||this.#C(e);o.setAttribute("href",v(e.getAttribute("href"))),o.onload=()=>{w(`\t${n}`),t()}}))}#k(e){return this.#R.find((t=>g(e.href)===g(t.href)))}get#R(){return Array.from(document.querySelectorAll("link[rel='stylesheet']"))}#C(e){return document.head.append(e),e}}class R{static async reload(){return(new R).reload()}async reload(){await this.#m()}async#m(){w("Reload html with Turbo..."),this.#M(),await this.#T()}#M(){document.addEventListener("turbo:before-render",(()=>{Turbo.navigator.currentVisit.scrolled=!0}),{once:!0})}#T(){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?k:R).reload(),reloadCss(e){const t=function(e){return e.split("/").pop().split(".")[0]}(e);return C.reload(new RegExp(t))},reloadStimulus:e=>A.reload(e)});const M={config:{loggingEnabled:!1,htmlReloadMethod:"morph"}},T={loggingEnabled:"logging",htmlReloadMethod:"html-reload-method"};return document.addEventListener("DOMContentLoaded",(function(){Object.entries(T).forEach((e=>{let[t,n]=e;var o;M.config[t]=(o=n,document.querySelector(`meta[name="hotwire-spark:${o}"]`)?.content)}))})),M}();
|
2
2
|
//# sourceMappingURL=hotwire_spark.min.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"hotwire_spark.min.js","sources":["../../../node_modules/@rails/actioncable/app/assets/javascripts/actioncable.esm.js","../../javascript/hotwire/spark/channels/consumer.js","../../javascript/hotwire/spark/helpers.js","../../../node_modules/idiomorph/dist/idiomorph.esm.js","../../javascript/hotwire/spark/logger.js","../../javascript/hotwire/spark/reloaders/stimulus_reloader.js","../../javascript/hotwire/spark/reloaders/morph_html_reloader.js","../../javascript/hotwire/spark/reloaders/css_reloader.js","../../javascript/hotwire/spark/reloaders/replace_html_reloader.js","../../javascript/hotwire/spark/channels/monitoring_channel.js","../../javascript/hotwire/spark/index.js"],"sourcesContent":["var adapters = {\n logger: typeof console !== \"undefined\" ? console : undefined,\n WebSocket: typeof WebSocket !== \"undefined\" ? WebSocket : undefined\n};\n\nvar logger = {\n log(...messages) {\n if (this.enabled) {\n messages.push(Date.now());\n adapters.logger.log(\"[ActionCable]\", ...messages);\n }\n }\n};\n\nconst now = () => (new Date).getTime();\n\nconst secondsSince = time => (now() - time) / 1e3;\n\nclass ConnectionMonitor {\n constructor(connection) {\n this.visibilityDidChange = this.visibilityDidChange.bind(this);\n this.connection = connection;\n this.reconnectAttempts = 0;\n }\n start() {\n if (!this.isRunning()) {\n this.startedAt = now();\n delete this.stoppedAt;\n this.startPolling();\n addEventListener(\"visibilitychange\", this.visibilityDidChange);\n logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`);\n }\n }\n stop() {\n if (this.isRunning()) {\n this.stoppedAt = now();\n this.stopPolling();\n removeEventListener(\"visibilitychange\", this.visibilityDidChange);\n logger.log(\"ConnectionMonitor stopped\");\n }\n }\n isRunning() {\n return this.startedAt && !this.stoppedAt;\n }\n recordMessage() {\n this.pingedAt = now();\n }\n recordConnect() {\n this.reconnectAttempts = 0;\n delete this.disconnectedAt;\n logger.log(\"ConnectionMonitor recorded connect\");\n }\n recordDisconnect() {\n this.disconnectedAt = now();\n logger.log(\"ConnectionMonitor recorded disconnect\");\n }\n startPolling() {\n this.stopPolling();\n this.poll();\n }\n stopPolling() {\n clearTimeout(this.pollTimeout);\n }\n poll() {\n this.pollTimeout = setTimeout((() => {\n this.reconnectIfStale();\n this.poll();\n }), this.getPollInterval());\n }\n getPollInterval() {\n const {staleThreshold: staleThreshold, reconnectionBackoffRate: reconnectionBackoffRate} = this.constructor;\n const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10));\n const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate;\n const jitter = jitterMax * Math.random();\n return staleThreshold * 1e3 * backoff * (1 + jitter);\n }\n reconnectIfStale() {\n if (this.connectionIsStale()) {\n logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`);\n this.reconnectAttempts++;\n if (this.disconnectedRecently()) {\n logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`);\n } else {\n logger.log(\"ConnectionMonitor reopening\");\n this.connection.reopen();\n }\n }\n }\n get refreshedAt() {\n return this.pingedAt ? this.pingedAt : this.startedAt;\n }\n connectionIsStale() {\n return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;\n }\n disconnectedRecently() {\n return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;\n }\n visibilityDidChange() {\n if (document.visibilityState === \"visible\") {\n setTimeout((() => {\n if (this.connectionIsStale() || !this.connection.isOpen()) {\n logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`);\n this.connection.reopen();\n }\n }), 200);\n }\n }\n}\n\nConnectionMonitor.staleThreshold = 6;\n\nConnectionMonitor.reconnectionBackoffRate = .15;\n\nvar INTERNAL = {\n message_types: {\n welcome: \"welcome\",\n disconnect: \"disconnect\",\n ping: \"ping\",\n confirmation: \"confirm_subscription\",\n rejection: \"reject_subscription\"\n },\n disconnect_reasons: {\n unauthorized: \"unauthorized\",\n invalid_request: \"invalid_request\",\n server_restart: \"server_restart\",\n remote: \"remote\"\n },\n default_mount_path: \"/cable\",\n protocols: [ \"actioncable-v1-json\", \"actioncable-unsupported\" ]\n};\n\nconst {message_types: message_types, protocols: protocols} = INTERNAL;\n\nconst supportedProtocols = protocols.slice(0, protocols.length - 1);\n\nconst indexOf = [].indexOf;\n\nclass Connection {\n constructor(consumer) {\n this.open = this.open.bind(this);\n this.consumer = consumer;\n this.subscriptions = this.consumer.subscriptions;\n this.monitor = new ConnectionMonitor(this);\n this.disconnected = true;\n }\n send(data) {\n if (this.isOpen()) {\n this.webSocket.send(JSON.stringify(data));\n return true;\n } else {\n return false;\n }\n }\n open() {\n if (this.isActive()) {\n logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);\n return false;\n } else {\n const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];\n logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);\n if (this.webSocket) {\n this.uninstallEventHandlers();\n }\n this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);\n this.installEventHandlers();\n this.monitor.start();\n return true;\n }\n }\n close({allowReconnect: allowReconnect} = {\n allowReconnect: true\n }) {\n if (!allowReconnect) {\n this.monitor.stop();\n }\n if (this.isOpen()) {\n return this.webSocket.close();\n }\n }\n reopen() {\n logger.log(`Reopening WebSocket, current state is ${this.getState()}`);\n if (this.isActive()) {\n try {\n return this.close();\n } catch (error) {\n logger.log(\"Failed to reopen WebSocket\", error);\n } finally {\n logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);\n setTimeout(this.open, this.constructor.reopenDelay);\n }\n } else {\n return this.open();\n }\n }\n getProtocol() {\n if (this.webSocket) {\n return this.webSocket.protocol;\n }\n }\n isOpen() {\n return this.isState(\"open\");\n }\n isActive() {\n return this.isState(\"open\", \"connecting\");\n }\n triedToReconnect() {\n return this.monitor.reconnectAttempts > 0;\n }\n isProtocolSupported() {\n return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;\n }\n isState(...states) {\n return indexOf.call(states, this.getState()) >= 0;\n }\n getState() {\n if (this.webSocket) {\n for (let state in adapters.WebSocket) {\n if (adapters.WebSocket[state] === this.webSocket.readyState) {\n return state.toLowerCase();\n }\n }\n }\n return null;\n }\n installEventHandlers() {\n for (let eventName in this.events) {\n const handler = this.events[eventName].bind(this);\n this.webSocket[`on${eventName}`] = handler;\n }\n }\n uninstallEventHandlers() {\n for (let eventName in this.events) {\n this.webSocket[`on${eventName}`] = function() {};\n }\n }\n}\n\nConnection.reopenDelay = 500;\n\nConnection.prototype.events = {\n message(event) {\n if (!this.isProtocolSupported()) {\n return;\n }\n const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);\n this.monitor.recordMessage();\n switch (type) {\n case message_types.welcome:\n if (this.triedToReconnect()) {\n this.reconnectAttempted = true;\n }\n this.monitor.recordConnect();\n return this.subscriptions.reload();\n\n case message_types.disconnect:\n logger.log(`Disconnecting. Reason: ${reason}`);\n return this.close({\n allowReconnect: reconnect\n });\n\n case message_types.ping:\n return null;\n\n case message_types.confirmation:\n this.subscriptions.confirmSubscription(identifier);\n if (this.reconnectAttempted) {\n this.reconnectAttempted = false;\n return this.subscriptions.notify(identifier, \"connected\", {\n reconnected: true\n });\n } else {\n return this.subscriptions.notify(identifier, \"connected\", {\n reconnected: false\n });\n }\n\n case message_types.rejection:\n return this.subscriptions.reject(identifier);\n\n default:\n return this.subscriptions.notify(identifier, \"received\", message);\n }\n },\n open() {\n logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);\n this.disconnected = false;\n if (!this.isProtocolSupported()) {\n logger.log(\"Protocol is unsupported. Stopping monitor and disconnecting.\");\n return this.close({\n allowReconnect: false\n });\n }\n },\n close(event) {\n logger.log(\"WebSocket onclose event\");\n if (this.disconnected) {\n return;\n }\n this.disconnected = true;\n this.monitor.recordDisconnect();\n return this.subscriptions.notifyAll(\"disconnected\", {\n willAttemptReconnect: this.monitor.isRunning()\n });\n },\n error() {\n logger.log(\"WebSocket onerror event\");\n }\n};\n\nconst extend = function(object, properties) {\n if (properties != null) {\n for (let key in properties) {\n const value = properties[key];\n object[key] = value;\n }\n }\n return object;\n};\n\nclass Subscription {\n constructor(consumer, params = {}, mixin) {\n this.consumer = consumer;\n this.identifier = JSON.stringify(params);\n extend(this, mixin);\n }\n perform(action, data = {}) {\n data.action = action;\n return this.send(data);\n }\n send(data) {\n return this.consumer.send({\n command: \"message\",\n identifier: this.identifier,\n data: JSON.stringify(data)\n });\n }\n unsubscribe() {\n return this.consumer.subscriptions.remove(this);\n }\n}\n\nclass SubscriptionGuarantor {\n constructor(subscriptions) {\n this.subscriptions = subscriptions;\n this.pendingSubscriptions = [];\n }\n guarantee(subscription) {\n if (this.pendingSubscriptions.indexOf(subscription) == -1) {\n logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`);\n this.pendingSubscriptions.push(subscription);\n } else {\n logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`);\n }\n this.startGuaranteeing();\n }\n forget(subscription) {\n logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`);\n this.pendingSubscriptions = this.pendingSubscriptions.filter((s => s !== subscription));\n }\n startGuaranteeing() {\n this.stopGuaranteeing();\n this.retrySubscribing();\n }\n stopGuaranteeing() {\n clearTimeout(this.retryTimeout);\n }\n retrySubscribing() {\n this.retryTimeout = setTimeout((() => {\n if (this.subscriptions && typeof this.subscriptions.subscribe === \"function\") {\n this.pendingSubscriptions.map((subscription => {\n logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`);\n this.subscriptions.subscribe(subscription);\n }));\n }\n }), 500);\n }\n}\n\nclass Subscriptions {\n constructor(consumer) {\n this.consumer = consumer;\n this.guarantor = new SubscriptionGuarantor(this);\n this.subscriptions = [];\n }\n create(channelName, mixin) {\n const channel = channelName;\n const params = typeof channel === \"object\" ? channel : {\n channel: channel\n };\n const subscription = new Subscription(this.consumer, params, mixin);\n return this.add(subscription);\n }\n add(subscription) {\n this.subscriptions.push(subscription);\n this.consumer.ensureActiveConnection();\n this.notify(subscription, \"initialized\");\n this.subscribe(subscription);\n return subscription;\n }\n remove(subscription) {\n this.forget(subscription);\n if (!this.findAll(subscription.identifier).length) {\n this.sendCommand(subscription, \"unsubscribe\");\n }\n return subscription;\n }\n reject(identifier) {\n return this.findAll(identifier).map((subscription => {\n this.forget(subscription);\n this.notify(subscription, \"rejected\");\n return subscription;\n }));\n }\n forget(subscription) {\n this.guarantor.forget(subscription);\n this.subscriptions = this.subscriptions.filter((s => s !== subscription));\n return subscription;\n }\n findAll(identifier) {\n return this.subscriptions.filter((s => s.identifier === identifier));\n }\n reload() {\n return this.subscriptions.map((subscription => this.subscribe(subscription)));\n }\n notifyAll(callbackName, ...args) {\n return this.subscriptions.map((subscription => this.notify(subscription, callbackName, ...args)));\n }\n notify(subscription, callbackName, ...args) {\n let subscriptions;\n if (typeof subscription === \"string\") {\n subscriptions = this.findAll(subscription);\n } else {\n subscriptions = [ subscription ];\n }\n return subscriptions.map((subscription => typeof subscription[callbackName] === \"function\" ? subscription[callbackName](...args) : undefined));\n }\n subscribe(subscription) {\n if (this.sendCommand(subscription, \"subscribe\")) {\n this.guarantor.guarantee(subscription);\n }\n }\n confirmSubscription(identifier) {\n logger.log(`Subscription confirmed ${identifier}`);\n this.findAll(identifier).map((subscription => this.guarantor.forget(subscription)));\n }\n sendCommand(subscription, command) {\n const {identifier: identifier} = subscription;\n return this.consumer.send({\n command: command,\n identifier: identifier\n });\n }\n}\n\nclass Consumer {\n constructor(url) {\n this._url = url;\n this.subscriptions = new Subscriptions(this);\n this.connection = new Connection(this);\n this.subprotocols = [];\n }\n get url() {\n return createWebSocketURL(this._url);\n }\n send(data) {\n return this.connection.send(data);\n }\n connect() {\n return this.connection.open();\n }\n disconnect() {\n return this.connection.close({\n allowReconnect: false\n });\n }\n ensureActiveConnection() {\n if (!this.connection.isActive()) {\n return this.connection.open();\n }\n }\n addSubProtocol(subprotocol) {\n this.subprotocols = [ ...this.subprotocols, subprotocol ];\n }\n}\n\nfunction createWebSocketURL(url) {\n if (typeof url === \"function\") {\n url = url();\n }\n if (url && !/^wss?:/i.test(url)) {\n const a = document.createElement(\"a\");\n a.href = url;\n a.href = a.href;\n a.protocol = a.protocol.replace(\"http\", \"ws\");\n return a.href;\n } else {\n return url;\n }\n}\n\nfunction createConsumer(url = getConfig(\"url\") || INTERNAL.default_mount_path) {\n return new Consumer(url);\n}\n\nfunction getConfig(name) {\n const element = document.head.querySelector(`meta[name='action-cable-${name}']`);\n if (element) {\n return element.getAttribute(\"content\");\n }\n}\n\nexport { Connection, ConnectionMonitor, Consumer, INTERNAL, Subscription, SubscriptionGuarantor, Subscriptions, adapters, createConsumer, createWebSocketURL, getConfig, logger };\n","import { createConsumer } from \"@rails/actioncable\"\n\nexport default createConsumer(\"/hotwire-spark\")\n","export function assetNameFromPath(path) {\n return path.split(\"/\").pop().split(\".\")[0]\n}\n\nexport function pathWithoutAssetDigest(path) {\n return path.replace(/-[a-z0-9]+\\.(\\w+)(\\?.*)?$/, \".$1\")\n}\n\nexport function urlWithParams(urlString, params) {\n const url = new URL(urlString, window.location.origin)\n Object.entries(params).forEach(([ key, value ]) => {\n url.searchParams.set(key, value)\n })\n return url.toString()\n}\n\nexport function cacheBustedUrl(urlString) {\n return urlWithParams(urlString, { reload: Date.now() })\n}\n\nexport async function reloadHtmlDocument() {\n let currentUrl = cacheBustedUrl(urlWithParams(window.location.href, { hotwire_spark: \"true\" }))\n const response = await fetch(currentUrl, { headers: { \"Accept\": \"text/html\" }})\n\n if (!response.ok) {\n throw new Error(`${response.status} when fetching ${currentUrl}`)\n }\n\n const fetchedHTML = await response.text()\n const parser = new DOMParser()\n return parser.parseFromString(fetchedHTML, \"text/html\")\n}\n\nexport function getConfigurationProperty(name) {\n return document.querySelector(`meta[name=\"hotwire-spark:${name}\"]`)?.content\n}\n\n","// base IIFE to define idiomorph\nvar Idiomorph = (function () {\n 'use strict';\n\n //=============================================================================\n // AND NOW IT BEGINS...\n //=============================================================================\n let EMPTY_SET = new Set();\n\n // default configuration values, updatable by users now\n let defaults = {\n morphStyle: \"outerHTML\",\n callbacks : {\n beforeNodeAdded: noOp,\n afterNodeAdded: noOp,\n beforeNodeMorphed: noOp,\n afterNodeMorphed: noOp,\n beforeNodeRemoved: noOp,\n afterNodeRemoved: noOp,\n beforeAttributeUpdated: noOp,\n\n },\n head: {\n style: 'merge',\n shouldPreserve: function (elt) {\n return elt.getAttribute(\"im-preserve\") === \"true\";\n },\n shouldReAppend: function (elt) {\n return elt.getAttribute(\"im-re-append\") === \"true\";\n },\n shouldRemove: noOp,\n afterHeadMorphed: noOp,\n }\n };\n\n //=============================================================================\n // Core Morphing Algorithm - morph, morphNormalizedContent, morphOldNodeTo, morphChildren\n //=============================================================================\n function morph(oldNode, newContent, config = {}) {\n\n if (oldNode instanceof Document) {\n oldNode = oldNode.documentElement;\n }\n\n if (typeof newContent === 'string') {\n newContent = parseContent(newContent);\n }\n\n let normalizedContent = normalizeContent(newContent);\n\n let ctx = createMorphContext(oldNode, normalizedContent, config);\n\n return morphNormalizedContent(oldNode, normalizedContent, ctx);\n }\n\n function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {\n if (ctx.head.block) {\n let oldHead = oldNode.querySelector('head');\n let newHead = normalizedNewContent.querySelector('head');\n if (oldHead && newHead) {\n let promises = handleHeadElement(newHead, oldHead, ctx);\n // when head promises resolve, call morph again, ignoring the head tag\n Promise.all(promises).then(function () {\n morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, {\n head: {\n block: false,\n ignore: true\n }\n }));\n });\n return;\n }\n }\n\n if (ctx.morphStyle === \"innerHTML\") {\n\n // innerHTML, so we are only updating the children\n morphChildren(normalizedNewContent, oldNode, ctx);\n return oldNode.children;\n\n } else if (ctx.morphStyle === \"outerHTML\" || ctx.morphStyle == null) {\n // otherwise find the best element match in the new content, morph that, and merge its siblings\n // into either side of the best match\n let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);\n\n // stash the siblings that will need to be inserted on either side of the best match\n let previousSibling = bestMatch?.previousSibling;\n let nextSibling = bestMatch?.nextSibling;\n\n // morph it\n let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);\n\n if (bestMatch) {\n // if there was a best match, merge the siblings in too and return the\n // whole bunch\n return insertSiblings(previousSibling, morphedNode, nextSibling);\n } else {\n // otherwise nothing was added to the DOM\n return []\n }\n } else {\n throw \"Do not understand how to morph style \" + ctx.morphStyle;\n }\n }\n\n\n /**\n * @param possibleActiveElement\n * @param ctx\n * @returns {boolean}\n */\n function ignoreValueOfActiveElement(possibleActiveElement, ctx) {\n return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement;\n }\n\n /**\n * @param oldNode root node to merge content into\n * @param newContent new content to merge\n * @param ctx the merge context\n * @returns {Element} the element that ended up in the DOM\n */\n function morphOldNodeTo(oldNode, newContent, ctx) {\n if (ctx.ignoreActive && oldNode === document.activeElement) {\n // don't morph focused element\n } else if (newContent == null) {\n if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;\n\n oldNode.remove();\n ctx.callbacks.afterNodeRemoved(oldNode);\n return null;\n } else if (!isSoftMatch(oldNode, newContent)) {\n if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;\n if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode;\n\n oldNode.parentElement.replaceChild(newContent, oldNode);\n ctx.callbacks.afterNodeAdded(newContent);\n ctx.callbacks.afterNodeRemoved(oldNode);\n return newContent;\n } else {\n if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode;\n\n if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) {\n // ignore the head element\n } else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== \"morph\") {\n handleHeadElement(newContent, oldNode, ctx);\n } else {\n syncNodeFrom(newContent, oldNode, ctx);\n if (!ignoreValueOfActiveElement(oldNode, ctx)) {\n morphChildren(newContent, oldNode, ctx);\n }\n }\n ctx.callbacks.afterNodeMorphed(oldNode, newContent);\n return oldNode;\n }\n }\n\n /**\n * This is the core algorithm for matching up children. The idea is to use id sets to try to match up\n * nodes as faithfully as possible. We greedily match, which allows us to keep the algorithm fast, but\n * by using id sets, we are able to better match up with content deeper in the DOM.\n *\n * Basic algorithm is, for each node in the new content:\n *\n * - if we have reached the end of the old parent, append the new content\n * - if the new content has an id set match with the current insertion point, morph\n * - search for an id set match\n * - if id set match found, morph\n * - otherwise search for a \"soft\" match\n * - if a soft match is found, morph\n * - otherwise, prepend the new node before the current insertion point\n *\n * The two search algorithms terminate if competing node matches appear to outweigh what can be achieved\n * with the current node. See findIdSetMatch() and findSoftMatch() for details.\n *\n * @param {Element} newParent the parent element of the new content\n * @param {Element } oldParent the old content that we are merging the new content into\n * @param ctx the merge context\n */\n function morphChildren(newParent, oldParent, ctx) {\n\n let nextNewChild = newParent.firstChild;\n let insertionPoint = oldParent.firstChild;\n let newChild;\n\n // run through all the new content\n while (nextNewChild) {\n\n newChild = nextNewChild;\n nextNewChild = newChild.nextSibling;\n\n // if we are at the end of the exiting parent's children, just append\n if (insertionPoint == null) {\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;\n\n oldParent.appendChild(newChild);\n ctx.callbacks.afterNodeAdded(newChild);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // if the current node has an id set match then morph\n if (isIdSetMatch(newChild, insertionPoint, ctx)) {\n morphOldNodeTo(insertionPoint, newChild, ctx);\n insertionPoint = insertionPoint.nextSibling;\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // otherwise search forward in the existing old children for an id set match\n let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);\n\n // if we found a potential match, remove the nodes until that point and morph\n if (idSetMatch) {\n insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);\n morphOldNodeTo(idSetMatch, newChild, ctx);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // no id set match found, so scan forward for a soft match for the current node\n let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);\n\n // if we found a soft match for the current node, morph\n if (softMatch) {\n insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);\n morphOldNodeTo(softMatch, newChild, ctx);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // abandon all hope of morphing, just insert the new child before the insertion point\n // and move on\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;\n\n oldParent.insertBefore(newChild, insertionPoint);\n ctx.callbacks.afterNodeAdded(newChild);\n removeIdsFromConsideration(ctx, newChild);\n }\n\n // remove any remaining old nodes that didn't match up with new content\n while (insertionPoint !== null) {\n\n let tempNode = insertionPoint;\n insertionPoint = insertionPoint.nextSibling;\n removeNode(tempNode, ctx);\n }\n }\n\n //=============================================================================\n // Attribute Syncing Code\n //=============================================================================\n\n /**\n * @param attr {String} the attribute to be mutated\n * @param to {Element} the element that is going to be updated\n * @param updateType {(\"update\"|\"remove\")}\n * @param ctx the merge context\n * @returns {boolean} true if the attribute should be ignored, false otherwise\n */\n function ignoreAttribute(attr, to, updateType, ctx) {\n if(attr === 'value' && ctx.ignoreActiveValue && to === document.activeElement){\n return true;\n }\n return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;\n }\n\n /**\n * syncs a given node with another node, copying over all attributes and\n * inner element state from the 'from' node to the 'to' node\n *\n * @param {Element} from the element to copy attributes & state from\n * @param {Element} to the element to copy attributes & state to\n * @param ctx the merge context\n */\n function syncNodeFrom(from, to, ctx) {\n let type = from.nodeType\n\n // if is an element type, sync the attributes from the\n // new node into the new node\n if (type === 1 /* element type */) {\n const fromAttributes = from.attributes;\n const toAttributes = to.attributes;\n for (const fromAttribute of fromAttributes) {\n if (ignoreAttribute(fromAttribute.name, to, 'update', ctx)) {\n continue;\n }\n if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) {\n to.setAttribute(fromAttribute.name, fromAttribute.value);\n }\n }\n // iterate backwards to avoid skipping over items when a delete occurs\n for (let i = toAttributes.length - 1; 0 <= i; i--) {\n const toAttribute = toAttributes[i];\n if (ignoreAttribute(toAttribute.name, to, 'remove', ctx)) {\n continue;\n }\n if (!from.hasAttribute(toAttribute.name)) {\n to.removeAttribute(toAttribute.name);\n }\n }\n }\n\n // sync text nodes\n if (type === 8 /* comment */ || type === 3 /* text */) {\n if (to.nodeValue !== from.nodeValue) {\n to.nodeValue = from.nodeValue;\n }\n }\n\n if (!ignoreValueOfActiveElement(to, ctx)) {\n // sync input values\n syncInputValue(from, to, ctx);\n }\n }\n\n /**\n * @param from {Element} element to sync the value from\n * @param to {Element} element to sync the value to\n * @param attributeName {String} the attribute name\n * @param ctx the merge context\n */\n function syncBooleanAttribute(from, to, attributeName, ctx) {\n if (from[attributeName] !== to[attributeName]) {\n let ignoreUpdate = ignoreAttribute(attributeName, to, 'update', ctx);\n if (!ignoreUpdate) {\n to[attributeName] = from[attributeName];\n }\n if (from[attributeName]) {\n if (!ignoreUpdate) {\n to.setAttribute(attributeName, from[attributeName]);\n }\n } else {\n if (!ignoreAttribute(attributeName, to, 'remove', ctx)) {\n to.removeAttribute(attributeName);\n }\n }\n }\n }\n\n /**\n * NB: many bothans died to bring us information:\n *\n * https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js\n * https://github.com/choojs/nanomorph/blob/master/lib/morph.jsL113\n *\n * @param from {Element} the element to sync the input value from\n * @param to {Element} the element to sync the input value to\n * @param ctx the merge context\n */\n function syncInputValue(from, to, ctx) {\n if (from instanceof HTMLInputElement &&\n to instanceof HTMLInputElement &&\n from.type !== 'file') {\n\n let fromValue = from.value;\n let toValue = to.value;\n\n // sync boolean attributes\n syncBooleanAttribute(from, to, 'checked', ctx);\n syncBooleanAttribute(from, to, 'disabled', ctx);\n\n if (!from.hasAttribute('value')) {\n if (!ignoreAttribute('value', to, 'remove', ctx)) {\n to.value = '';\n to.removeAttribute('value');\n }\n } else if (fromValue !== toValue) {\n if (!ignoreAttribute('value', to, 'update', ctx)) {\n to.setAttribute('value', fromValue);\n to.value = fromValue;\n }\n }\n } else if (from instanceof HTMLOptionElement) {\n syncBooleanAttribute(from, to, 'selected', ctx)\n } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {\n let fromValue = from.value;\n let toValue = to.value;\n if (ignoreAttribute('value', to, 'update', ctx)) {\n return;\n }\n if (fromValue !== toValue) {\n to.value = fromValue;\n }\n if (to.firstChild && to.firstChild.nodeValue !== fromValue) {\n to.firstChild.nodeValue = fromValue\n }\n }\n }\n\n //=============================================================================\n // the HEAD tag can be handled specially, either w/ a 'merge' or 'append' style\n //=============================================================================\n function handleHeadElement(newHeadTag, currentHead, ctx) {\n\n let added = []\n let removed = []\n let preserved = []\n let nodesToAppend = []\n\n let headMergeStyle = ctx.head.style;\n\n // put all new head elements into a Map, by their outerHTML\n let srcToNewHeadNodes = new Map();\n for (const newHeadChild of newHeadTag.children) {\n srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);\n }\n\n // for each elt in the current head\n for (const currentHeadElt of currentHead.children) {\n\n // If the current head element is in the map\n let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);\n let isReAppended = ctx.head.shouldReAppend(currentHeadElt);\n let isPreserved = ctx.head.shouldPreserve(currentHeadElt);\n if (inNewContent || isPreserved) {\n if (isReAppended) {\n // remove the current version and let the new version replace it and re-execute\n removed.push(currentHeadElt);\n } else {\n // this element already exists and should not be re-appended, so remove it from\n // the new content map, preserving it in the DOM\n srcToNewHeadNodes.delete(currentHeadElt.outerHTML);\n preserved.push(currentHeadElt);\n }\n } else {\n if (headMergeStyle === \"append\") {\n // we are appending and this existing element is not new content\n // so if and only if it is marked for re-append do we do anything\n if (isReAppended) {\n removed.push(currentHeadElt);\n nodesToAppend.push(currentHeadElt);\n }\n } else {\n // if this is a merge, we remove this content since it is not in the new head\n if (ctx.head.shouldRemove(currentHeadElt) !== false) {\n removed.push(currentHeadElt);\n }\n }\n }\n }\n\n // Push the remaining new head elements in the Map into the\n // nodes to append to the head tag\n nodesToAppend.push(...srcToNewHeadNodes.values());\n log(\"to append: \", nodesToAppend);\n\n let promises = [];\n for (const newNode of nodesToAppend) {\n log(\"adding: \", newNode);\n let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;\n log(newElt);\n if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {\n if (newElt.href || newElt.src) {\n let resolve = null;\n let promise = new Promise(function (_resolve) {\n resolve = _resolve;\n });\n newElt.addEventListener('load', function () {\n resolve();\n });\n promises.push(promise);\n }\n currentHead.appendChild(newElt);\n ctx.callbacks.afterNodeAdded(newElt);\n added.push(newElt);\n }\n }\n\n // remove all removed elements, after we have appended the new elements to avoid\n // additional network requests for things like style sheets\n for (const removedElement of removed) {\n if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {\n currentHead.removeChild(removedElement);\n ctx.callbacks.afterNodeRemoved(removedElement);\n }\n }\n\n ctx.head.afterHeadMorphed(currentHead, {added: added, kept: preserved, removed: removed});\n return promises;\n }\n\n //=============================================================================\n // Misc\n //=============================================================================\n\n function log() {\n //console.log(arguments);\n }\n\n function noOp() {\n }\n\n /*\n Deep merges the config object and the Idiomoroph.defaults object to\n produce a final configuration object\n */\n function mergeDefaults(config) {\n let finalConfig = {};\n // copy top level stuff into final config\n Object.assign(finalConfig, defaults);\n Object.assign(finalConfig, config);\n\n // copy callbacks into final config (do this to deep merge the callbacks)\n finalConfig.callbacks = {};\n Object.assign(finalConfig.callbacks, defaults.callbacks);\n Object.assign(finalConfig.callbacks, config.callbacks);\n\n // copy head config into final config (do this to deep merge the head)\n finalConfig.head = {};\n Object.assign(finalConfig.head, defaults.head);\n Object.assign(finalConfig.head, config.head);\n return finalConfig;\n }\n\n function createMorphContext(oldNode, newContent, config) {\n config = mergeDefaults(config);\n return {\n target: oldNode,\n newContent: newContent,\n config: config,\n morphStyle: config.morphStyle,\n ignoreActive: config.ignoreActive,\n ignoreActiveValue: config.ignoreActiveValue,\n idMap: createIdMap(oldNode, newContent),\n deadIds: new Set(),\n callbacks: config.callbacks,\n head: config.head\n }\n }\n\n function isIdSetMatch(node1, node2, ctx) {\n if (node1 == null || node2 == null) {\n return false;\n }\n if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) {\n if (node1.id !== \"\" && node1.id === node2.id) {\n return true;\n } else {\n return getIdIntersectionCount(ctx, node1, node2) > 0;\n }\n }\n return false;\n }\n\n function isSoftMatch(node1, node2) {\n if (node1 == null || node2 == null) {\n return false;\n }\n return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName\n }\n\n function removeNodesBetween(startInclusive, endExclusive, ctx) {\n while (startInclusive !== endExclusive) {\n let tempNode = startInclusive;\n startInclusive = startInclusive.nextSibling;\n removeNode(tempNode, ctx);\n }\n removeIdsFromConsideration(ctx, endExclusive);\n return endExclusive.nextSibling;\n }\n\n //=============================================================================\n // Scans forward from the insertionPoint in the old parent looking for a potential id match\n // for the newChild. We stop if we find a potential id match for the new child OR\n // if the number of potential id matches we are discarding is greater than the\n // potential id matches for the new child\n //=============================================================================\n function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {\n\n // max id matches we are willing to discard in our search\n let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);\n\n let potentialMatch = null;\n\n // only search forward if there is a possibility of an id match\n if (newChildPotentialIdCount > 0) {\n let potentialMatch = insertionPoint;\n // if there is a possibility of an id match, scan forward\n // keep track of the potential id match count we are discarding (the\n // newChildPotentialIdCount must be greater than this to make it likely\n // worth it)\n let otherMatchCount = 0;\n while (potentialMatch != null) {\n\n // If we have an id match, return the current potential match\n if (isIdSetMatch(newChild, potentialMatch, ctx)) {\n return potentialMatch;\n }\n\n // computer the other potential matches of this new content\n otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent);\n if (otherMatchCount > newChildPotentialIdCount) {\n // if we have more potential id matches in _other_ content, we\n // do not have a good candidate for an id match, so return null\n return null;\n }\n\n // advanced to the next old content child\n potentialMatch = potentialMatch.nextSibling;\n }\n }\n return potentialMatch;\n }\n\n //=============================================================================\n // Scans forward from the insertionPoint in the old parent looking for a potential soft match\n // for the newChild. We stop if we find a potential soft match for the new child OR\n // if we find a potential id match in the old parents children OR if we find two\n // potential soft matches for the next two pieces of new content\n //=============================================================================\n function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {\n\n let potentialSoftMatch = insertionPoint;\n let nextSibling = newChild.nextSibling;\n let siblingSoftMatchCount = 0;\n\n while (potentialSoftMatch != null) {\n\n if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {\n // the current potential soft match has a potential id set match with the remaining new\n // content so bail out of looking\n return null;\n }\n\n // if we have a soft match with the current node, return it\n if (isSoftMatch(newChild, potentialSoftMatch)) {\n return potentialSoftMatch;\n }\n\n if (isSoftMatch(nextSibling, potentialSoftMatch)) {\n // the next new node has a soft match with this node, so\n // increment the count of future soft matches\n siblingSoftMatchCount++;\n nextSibling = nextSibling.nextSibling;\n\n // If there are two future soft matches, bail to allow the siblings to soft match\n // so that we don't consume future soft matches for the sake of the current node\n if (siblingSoftMatchCount >= 2) {\n return null;\n }\n }\n\n // advanced to the next old content child\n potentialSoftMatch = potentialSoftMatch.nextSibling;\n }\n\n return potentialSoftMatch;\n }\n\n function parseContent(newContent) {\n let parser = new DOMParser();\n\n // remove svgs to avoid false-positive matches on head, etc.\n let contentWithSvgsRemoved = newContent.replace(/<svg(\\s[^>]*>|>)([\\s\\S]*?)<\\/svg>/gim, '');\n\n // if the newContent contains a html, head or body tag, we can simply parse it w/o wrapping\n if (contentWithSvgsRemoved.match(/<\\/html>/) || contentWithSvgsRemoved.match(/<\\/head>/) || contentWithSvgsRemoved.match(/<\\/body>/)) {\n let content = parser.parseFromString(newContent, \"text/html\");\n // if it is a full HTML document, return the document itself as the parent container\n if (contentWithSvgsRemoved.match(/<\\/html>/)) {\n content.generatedByIdiomorph = true;\n return content;\n } else {\n // otherwise return the html element as the parent container\n let htmlElement = content.firstChild;\n if (htmlElement) {\n htmlElement.generatedByIdiomorph = true;\n return htmlElement;\n } else {\n return null;\n }\n }\n } else {\n // if it is partial HTML, wrap it in a template tag to provide a parent element and also to help\n // deal with touchy tags like tr, tbody, etc.\n let responseDoc = parser.parseFromString(\"<body><template>\" + newContent + \"</template></body>\", \"text/html\");\n let content = responseDoc.body.querySelector('template').content;\n content.generatedByIdiomorph = true;\n return content\n }\n }\n\n function normalizeContent(newContent) {\n if (newContent == null) {\n // noinspection UnnecessaryLocalVariableJS\n const dummyParent = document.createElement('div');\n return dummyParent;\n } else if (newContent.generatedByIdiomorph) {\n // the template tag created by idiomorph parsing can serve as a dummy parent\n return newContent;\n } else if (newContent instanceof Node) {\n // a single node is added as a child to a dummy parent\n const dummyParent = document.createElement('div');\n dummyParent.append(newContent);\n return dummyParent;\n } else {\n // all nodes in the array or HTMLElement collection are consolidated under\n // a single dummy parent element\n const dummyParent = document.createElement('div');\n for (const elt of [...newContent]) {\n dummyParent.append(elt);\n }\n return dummyParent;\n }\n }\n\n function insertSiblings(previousSibling, morphedNode, nextSibling) {\n let stack = []\n let added = []\n while (previousSibling != null) {\n stack.push(previousSibling);\n previousSibling = previousSibling.previousSibling;\n }\n while (stack.length > 0) {\n let node = stack.pop();\n added.push(node); // push added preceding siblings on in order and insert\n morphedNode.parentElement.insertBefore(node, morphedNode);\n }\n added.push(morphedNode);\n while (nextSibling != null) {\n stack.push(nextSibling);\n added.push(nextSibling); // here we are going in order, so push on as we scan, rather than add\n nextSibling = nextSibling.nextSibling;\n }\n while (stack.length > 0) {\n morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);\n }\n return added;\n }\n\n function findBestNodeMatch(newContent, oldNode, ctx) {\n let currentElement;\n currentElement = newContent.firstChild;\n let bestElement = currentElement;\n let score = 0;\n while (currentElement) {\n let newScore = scoreElement(currentElement, oldNode, ctx);\n if (newScore > score) {\n bestElement = currentElement;\n score = newScore;\n }\n currentElement = currentElement.nextSibling;\n }\n return bestElement;\n }\n\n function scoreElement(node1, node2, ctx) {\n if (isSoftMatch(node1, node2)) {\n return .5 + getIdIntersectionCount(ctx, node1, node2);\n }\n return 0;\n }\n\n function removeNode(tempNode, ctx) {\n removeIdsFromConsideration(ctx, tempNode)\n if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;\n\n tempNode.remove();\n ctx.callbacks.afterNodeRemoved(tempNode);\n }\n\n //=============================================================================\n // ID Set Functions\n //=============================================================================\n\n function isIdInConsideration(ctx, id) {\n return !ctx.deadIds.has(id);\n }\n\n function idIsWithinNode(ctx, id, targetNode) {\n let idSet = ctx.idMap.get(targetNode) || EMPTY_SET;\n return idSet.has(id);\n }\n\n function removeIdsFromConsideration(ctx, node) {\n let idSet = ctx.idMap.get(node) || EMPTY_SET;\n for (const id of idSet) {\n ctx.deadIds.add(id);\n }\n }\n\n function getIdIntersectionCount(ctx, node1, node2) {\n let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;\n let matchCount = 0;\n for (const id of sourceSet) {\n // a potential match is an id in the source and potentialIdsSet, but\n // that has not already been merged into the DOM\n if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) {\n ++matchCount;\n }\n }\n return matchCount;\n }\n\n /**\n * A bottom up algorithm that finds all elements with ids inside of the node\n * argument and populates id sets for those nodes and all their parents, generating\n * a set of ids contained within all nodes for the entire hierarchy in the DOM\n *\n * @param node {Element}\n * @param {Map<Node, Set<String>>} idMap\n */\n function populateIdMapForNode(node, idMap) {\n let nodeParent = node.parentElement;\n // find all elements with an id property\n let idElements = node.querySelectorAll('[id]');\n for (const elt of idElements) {\n let current = elt;\n // walk up the parent hierarchy of that element, adding the id\n // of element to the parent's id set\n while (current !== nodeParent && current != null) {\n let idSet = idMap.get(current);\n // if the id set doesn't exist, create it and insert it in the map\n if (idSet == null) {\n idSet = new Set();\n idMap.set(current, idSet);\n }\n idSet.add(elt.id);\n current = current.parentElement;\n }\n }\n }\n\n /**\n * This function computes a map of nodes to all ids contained within that node (inclusive of the\n * node). This map can be used to ask if two nodes have intersecting sets of ids, which allows\n * for a looser definition of \"matching\" than tradition id matching, and allows child nodes\n * to contribute to a parent nodes matching.\n *\n * @param {Element} oldContent the old content that will be morphed\n * @param {Element} newContent the new content to morph to\n * @returns {Map<Node, Set<String>>} a map of nodes to id sets for the\n */\n function createIdMap(oldContent, newContent) {\n let idMap = new Map();\n populateIdMapForNode(oldContent, idMap);\n populateIdMapForNode(newContent, idMap);\n return idMap;\n }\n\n //=============================================================================\n // This is what ends up becoming the Idiomorph global object\n //=============================================================================\n return {\n morph,\n defaults\n }\n })();\n\nexport {Idiomorph};\n","import HotwireSpark from \"./index.js\"\n\nexport function log(...args) {\n if (HotwireSpark.config.loggingEnabled) {\n console.log(`[hotwire_spark]`, ...args)\n }\n}\n\n","import { log } from \"../logger.js\"\n\nexport class StimulusReloader {\n static async reload(path) {\n return new StimulusReloader(path).reload()\n }\n\n static async reloadAll() {\n Stimulus.controllers.forEach(controller => {\n Stimulus.unload(controller.identifier)\n Stimulus.register(controller.identifier, controller.constructor)\n })\n\n return Promise.resolve()\n }\n\n constructor(changedPath) {\n this.changedPath = changedPath\n this.application = window.Stimulus\n }\n\n async reload() {\n log(\"Reload Stimulus controllers...\")\n\n this.application.stop()\n\n try {\n await this.#reloadChangedController()\n }\n catch(error) {\n if (error instanceof SourceFileNotFound) {\n this.#deregisterChangedController()\n } else {\n console.error(\"Error reloading controller\", error)\n }\n }\n\n this.application.start()\n }\n\n async #reloadChangedController() {\n const module = await this.#importControllerFromSource(this.changedPath)\n await this.#registerController(this.#changedControllerIdentifier, module)\n }\n\n async #importControllerFromSource(path) {\n const response = await fetch(`/spark/source_files/?path=${path}`)\n\n if (response.status === 404) {\n throw new SourceFileNotFound(`Source file not found: ${path}`)\n }\n\n const sourceCode = await response.text()\n\n const blob = new Blob([sourceCode], { type: \"application/javascript\" })\n const moduleUrl = URL.createObjectURL(blob)\n const module = await import(moduleUrl)\n URL.revokeObjectURL(moduleUrl)\n\n return module\n }\n\n get #changedControllerIdentifier() {\n this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.changedPath)\n return this.changedControllerIdentifier\n }\n\n #extractControllerName(path) {\n return path\n .replace(/^.*\\//, \"\")\n .replace(\"_controller\", \"\")\n .replace(/\\//g, \"--\")\n .replace(/_/g, \"-\")\n .replace(/\\.js$/, \"\")\n }\n\n #deregisterChangedController() {\n this.#deregisterController(this.#changedControllerIdentifier)\n }\n\n #registerController(name, module) {\n log(\"\\tReloading controller\", name)\n\n this.application.unload(name)\n this.application.register(name, module.default)\n }\n\n #deregisterController(name) {\n log(`\\tRemoving controller ${name}`)\n this.application.unload(name)\n }\n}\n\nclass SourceFileNotFound extends Error { }\n","import { Idiomorph } from \"idiomorph/dist/idiomorph.esm.js\"\nimport { reloadHtmlDocument } from \"../helpers.js\"\nimport { log } from \"../logger.js\"\nimport { StimulusReloader } from \"./stimulus_reloader.js\"\n\nexport class MorphHtmlReloader {\n static async reload() {\n return new MorphHtmlReloader().reload()\n }\n\n async reload() {\n await this.#reloadHtml()\n await this.#reloadStimulus()\n }\n\n async #reloadHtml() {\n log(\"Reload html with morph...\")\n\n const reloadedDocument = await reloadHtmlDocument()\n this.#updateBody(reloadedDocument.body)\n return reloadedDocument\n }\n\n #updateBody(newBody) {\n Idiomorph.morph(document.body, newBody)\n }\n\n async #reloadStimulus() {\n await StimulusReloader.reloadAll()\n }\n}\n","import { log } from \"../logger.js\"\nimport { cacheBustedUrl, reloadHtmlDocument, pathWithoutAssetDigest } from \"../helpers.js\"\n\nexport class CssReloader {\n static async reload(...params) {\n return new CssReloader(...params).reload()\n }\n\n constructor(filePattern = /./) {\n this.filePattern = filePattern\n }\n\n async reload() {\n log(\"Reload css...\")\n await Promise.all(await this.#reloadAllLinks())\n }\n\n async #reloadAllLinks() {\n const cssLinks = await this.#loadNewCssLinks();\n return cssLinks.map(link => this.#reloadLinkIfNeeded(link))\n }\n\n async #loadNewCssLinks() {\n const reloadedDocument = await reloadHtmlDocument()\n return Array.from(reloadedDocument.head.querySelectorAll(\"link[rel='stylesheet']\"))\n }\n\n #reloadLinkIfNeeded(link) {\n if (this.#shouldReloadLink(link)) {\n return this.#reloadLink(link)\n } else {\n return Promise.resolve()\n }\n }\n\n #shouldReloadLink(link) {\n return this.filePattern.test(link.getAttribute(\"href\"))\n }\n\n async #reloadLink(link) {\n return new Promise(resolve => {\n const href = link.getAttribute(\"href\")\n const newLink = this.#findExistingLinkFor(link) || this.#appendNewLink(link)\n\n newLink.setAttribute(\"href\", cacheBustedUrl(link.getAttribute(\"href\")))\n newLink.onload = () => {\n log(`\\t${href}`)\n resolve()\n }\n })\n }\n\n #findExistingLinkFor(link) {\n return this.#cssLinks.find(newLink => pathWithoutAssetDigest(link.href) === pathWithoutAssetDigest(newLink.href))\n }\n\n get #cssLinks() {\n return Array.from(document.querySelectorAll(\"link[rel='stylesheet']\"))\n }\n\n #appendNewLink(link) {\n document.head.append(link)\n return link\n }\n}\n","import { log } from \"../logger.js\"\n\nexport class ReplaceHtmlReloader {\n static async reload() {\n return new ReplaceHtmlReloader().reload()\n }\n\n async reload() {\n await this.#reloadHtml()\n }\n\n async #reloadHtml() {\n log(\"Reload html with Turbo...\")\n\n this.#maintainScrollPosition()\n await this.#visitCurrentPage()\n }\n\n #maintainScrollPosition() {\n document.addEventListener(\"turbo:before-render\", () => {\n Turbo.navigator.currentVisit.scrolled = true\n }, { once: true })\n }\n\n #visitCurrentPage() {\n return new Promise(resolve => {\n document.addEventListener(\"turbo:load\", () => resolve(document), { once: true })\n window.Turbo.visit(window.location)\n })\n }\n}\n","import consumer from \"./consumer\"\nimport { assetNameFromPath } from \"../helpers.js\";\nimport { MorphHtmlReloader } from \"../reloaders/morph_html_reloader.js\";\nimport { CssReloader } from \"../reloaders/css_reloader.js\";\nimport { StimulusReloader } from \"../reloaders/stimulus_reloader.js\";\nimport { ReplaceHtmlReloader } from \"../reloaders/replace_html_reloader.js\";\n\nconsumer.subscriptions.create({ channel: \"Hotwire::Spark::Channel\" }, {\n connected() {\n document.body.setAttribute(\"data-hotwire-spark-ready\", \"\")\n },\n\n async received(message) {\n try {\n await this.dispatch(message)\n } catch(error) {\n console.log(`Error on ${message.action}`, error)\n }\n },\n\n dispatch({ action, path }) {\n switch(action) {\n case \"reload_html\":\n return this.reloadHtml()\n case \"reload_css\":\n return this.reloadCss(path)\n case \"reload_stimulus\":\n return this.reloadStimulus(path)\n default:\n throw new Error(`Unknown action: ${action}`)\n }\n },\n\n reloadHtml() {\n const htmlReloader = HotwireSpark.config.htmlReloadMethod == \"morph\" ? MorphHtmlReloader : ReplaceHtmlReloader\n return htmlReloader.reload()\n },\n\n reloadCss(path) {\n const fileName = assetNameFromPath(path)\n return CssReloader.reload(new RegExp(fileName))\n },\n\n reloadStimulus(path) {\n return StimulusReloader.reload(path)\n }\n})\n\n","import \"./channels/monitoring_channel.js\"\nimport { getConfigurationProperty } from \"./helpers.js\";\n\nconst HotwireSpark = {\n config: {\n loggingEnabled: false,\n htmlReloadMethod: \"morph\"\n }\n}\n\nconst configProperties = {\n loggingEnabled: \"logging\",\n htmlReloadMethod: \"html-reload-method\",\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n Object.entries(configProperties).forEach(([key, property]) => {\n HotwireSpark.config[key] = getConfigurationProperty(property)\n })\n})\n\nexport default HotwireSpark\n"],"names":["adapters","logger","console","undefined","WebSocket","log","messages","this","enabled","push","Date","now","getTime","secondsSince","time","ConnectionMonitor","constructor","connection","visibilityDidChange","bind","reconnectAttempts","start","isRunning","startedAt","stoppedAt","startPolling","addEventListener","staleThreshold","stop","stopPolling","removeEventListener","recordMessage","pingedAt","recordConnect","disconnectedAt","recordDisconnect","poll","clearTimeout","pollTimeout","setTimeout","reconnectIfStale","getPollInterval","reconnectionBackoffRate","Math","pow","min","random","connectionIsStale","refreshedAt","disconnectedRecently","reopen","document","visibilityState","isOpen","INTERNAL","message_types","welcome","disconnect","ping","confirmation","rejection","disconnect_reasons","unauthorized","invalid_request","server_restart","remote","default_mount_path","protocols","supportedProtocols","slice","length","indexOf","Connection","consumer","open","subscriptions","monitor","disconnected","send","data","webSocket","JSON","stringify","isActive","getState","socketProtocols","subprotocols","uninstallEventHandlers","url","installEventHandlers","close","allowReconnect","error","reopenDelay","getProtocol","protocol","isState","triedToReconnect","isProtocolSupported","call","states","state","readyState","toLowerCase","eventName","events","handler","prototype","message","event","identifier","reason","reconnect","type","parse","reconnectAttempted","reload","confirmSubscription","notify","reconnected","reject","notifyAll","willAttemptReconnect","Subscription","params","mixin","object","properties","key","value","extend","perform","action","command","unsubscribe","remove","SubscriptionGuarantor","pendingSubscriptions","guarantee","subscription","startGuaranteeing","forget","filter","s","stopGuaranteeing","retrySubscribing","retryTimeout","subscribe","map","Subscriptions","guarantor","create","channelName","channel","add","ensureActiveConnection","findAll","sendCommand","callbackName","args","Consumer","_url","test","a","createElement","href","replace","createWebSocketURL","connect","addSubProtocol","subprotocol","createConsumer","name","element","head","querySelector","getAttribute","getConfig","pathWithoutAssetDigest","path","urlWithParams","urlString","URL","window","location","origin","Object","entries","forEach","_ref","searchParams","set","toString","cacheBustedUrl","async","reloadHtmlDocument","currentUrl","hotwire_spark","response","fetch","headers","Accept","ok","Error","status","fetchedHTML","text","DOMParser","parseFromString","Idiomorph","EMPTY_SET","Set","defaults","morphStyle","callbacks","beforeNodeAdded","noOp","afterNodeAdded","beforeNodeMorphed","afterNodeMorphed","beforeNodeRemoved","afterNodeRemoved","beforeAttributeUpdated","style","shouldPreserve","elt","shouldReAppend","shouldRemove","afterHeadMorphed","morphNormalizedContent","oldNode","normalizedNewContent","ctx","block","oldHead","newHead","promises","handleHeadElement","Promise","all","then","assign","ignore","morphChildren","children","bestMatch","newContent","currentElement","firstChild","bestElement","score","newScore","scoreElement","nextSibling","findBestNodeMatch","previousSibling","morphedNode","morphOldNodeTo","stack","added","node","pop","parentElement","insertBefore","insertSiblings","ignoreValueOfActiveElement","possibleActiveElement","ignoreActiveValue","activeElement","ignoreActive","isSoftMatch","HTMLHeadElement","from","to","nodeType","fromAttributes","attributes","toAttributes","fromAttribute","ignoreAttribute","setAttribute","i","toAttribute","hasAttribute","removeAttribute","nodeValue","HTMLInputElement","fromValue","toValue","syncBooleanAttribute","HTMLOptionElement","HTMLTextAreaElement","syncInputValue","syncNodeFrom","replaceChild","newParent","oldParent","newChild","nextNewChild","insertionPoint","appendChild","removeIdsFromConsideration","isIdSetMatch","idSetMatch","findIdSetMatch","removeNodesBetween","softMatch","findSoftMatch","tempNode","removeNode","attr","updateType","attributeName","ignoreUpdate","newHeadTag","currentHead","removed","preserved","nodesToAppend","headMergeStyle","srcToNewHeadNodes","Map","newHeadChild","outerHTML","currentHeadElt","inNewContent","has","isReAppended","isPreserved","delete","values","newNode","newElt","createRange","createContextualFragment","src","resolve","promise","_resolve","removedElement","removeChild","kept","node1","node2","tagName","id","getIdIntersectionCount","startInclusive","endExclusive","newChildPotentialIdCount","potentialMatch","otherMatchCount","potentialSoftMatch","siblingSoftMatchCount","isIdInConsideration","deadIds","idIsWithinNode","targetNode","idMap","get","idSet","sourceSet","matchCount","populateIdMapForNode","nodeParent","idElements","querySelectorAll","current","createIdMap","oldContent","morph","config","Document","documentElement","parser","contentWithSvgsRemoved","match","content","generatedByIdiomorph","htmlElement","body","parseContent","normalizedContent","Node","dummyParent","append","normalizeContent","finalConfig","mergeDefaults","target","createMorphContext","HotwireSpark","loggingEnabled","_len","arguments","Array","_key","StimulusReloader","reloadAll","Stimulus","controllers","controller","unload","register","changedPath","application","reloadChangedController","SourceFileNotFound","deregisterChangedController","module","importControllerFromSource","registerController","changedControllerIdentifier","sourceCode","blob","Blob","moduleUrl","createObjectURL","import","revokeObjectURL","extractControllerName","deregisterController","default","MorphHtmlReloader","reloadHtml","reloadStimulus","reloadedDocument","updateBody","newBody","CssReloader","filePattern","reloadAllLinks","loadNewCssLinks","link","reloadLinkIfNeeded","shouldReloadLink","reloadLink","newLink","findExistingLinkFor","appendNewLink","onload","cssLinks","find","ReplaceHtmlReloader","maintainScrollPosition","visitCurrentPage","Turbo","navigator","currentVisit","scrolled","once","visit","connected","received","dispatch","reloadCss","htmlReloadMethod","fileName","split","assetNameFromPath","RegExp","configProperties","property"],"mappings":"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","x_google_ignoreList":[0,3]}
|
1
|
+
{"version":3,"file":"hotwire_spark.min.js","sources":["../../../node_modules/@rails/actioncable/app/assets/javascripts/actioncable.esm.js","../../javascript/hotwire/spark/channels/consumer.js","../../javascript/hotwire/spark/helpers.js","../../../node_modules/idiomorph/dist/idiomorph.esm.js","../../javascript/hotwire/spark/logger.js","../../javascript/hotwire/spark/reloaders/stimulus_reloader.js","../../javascript/hotwire/spark/reloaders/morph_html_reloader.js","../../javascript/hotwire/spark/reloaders/css_reloader.js","../../javascript/hotwire/spark/reloaders/replace_html_reloader.js","../../javascript/hotwire/spark/channels/monitoring_channel.js","../../javascript/hotwire/spark/index.js"],"sourcesContent":["var adapters = {\n logger: typeof console !== \"undefined\" ? console : undefined,\n WebSocket: typeof WebSocket !== \"undefined\" ? WebSocket : undefined\n};\n\nvar logger = {\n log(...messages) {\n if (this.enabled) {\n messages.push(Date.now());\n adapters.logger.log(\"[ActionCable]\", ...messages);\n }\n }\n};\n\nconst now = () => (new Date).getTime();\n\nconst secondsSince = time => (now() - time) / 1e3;\n\nclass ConnectionMonitor {\n constructor(connection) {\n this.visibilityDidChange = this.visibilityDidChange.bind(this);\n this.connection = connection;\n this.reconnectAttempts = 0;\n }\n start() {\n if (!this.isRunning()) {\n this.startedAt = now();\n delete this.stoppedAt;\n this.startPolling();\n addEventListener(\"visibilitychange\", this.visibilityDidChange);\n logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`);\n }\n }\n stop() {\n if (this.isRunning()) {\n this.stoppedAt = now();\n this.stopPolling();\n removeEventListener(\"visibilitychange\", this.visibilityDidChange);\n logger.log(\"ConnectionMonitor stopped\");\n }\n }\n isRunning() {\n return this.startedAt && !this.stoppedAt;\n }\n recordMessage() {\n this.pingedAt = now();\n }\n recordConnect() {\n this.reconnectAttempts = 0;\n delete this.disconnectedAt;\n logger.log(\"ConnectionMonitor recorded connect\");\n }\n recordDisconnect() {\n this.disconnectedAt = now();\n logger.log(\"ConnectionMonitor recorded disconnect\");\n }\n startPolling() {\n this.stopPolling();\n this.poll();\n }\n stopPolling() {\n clearTimeout(this.pollTimeout);\n }\n poll() {\n this.pollTimeout = setTimeout((() => {\n this.reconnectIfStale();\n this.poll();\n }), this.getPollInterval());\n }\n getPollInterval() {\n const {staleThreshold: staleThreshold, reconnectionBackoffRate: reconnectionBackoffRate} = this.constructor;\n const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10));\n const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate;\n const jitter = jitterMax * Math.random();\n return staleThreshold * 1e3 * backoff * (1 + jitter);\n }\n reconnectIfStale() {\n if (this.connectionIsStale()) {\n logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`);\n this.reconnectAttempts++;\n if (this.disconnectedRecently()) {\n logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`);\n } else {\n logger.log(\"ConnectionMonitor reopening\");\n this.connection.reopen();\n }\n }\n }\n get refreshedAt() {\n return this.pingedAt ? this.pingedAt : this.startedAt;\n }\n connectionIsStale() {\n return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;\n }\n disconnectedRecently() {\n return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;\n }\n visibilityDidChange() {\n if (document.visibilityState === \"visible\") {\n setTimeout((() => {\n if (this.connectionIsStale() || !this.connection.isOpen()) {\n logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`);\n this.connection.reopen();\n }\n }), 200);\n }\n }\n}\n\nConnectionMonitor.staleThreshold = 6;\n\nConnectionMonitor.reconnectionBackoffRate = .15;\n\nvar INTERNAL = {\n message_types: {\n welcome: \"welcome\",\n disconnect: \"disconnect\",\n ping: \"ping\",\n confirmation: \"confirm_subscription\",\n rejection: \"reject_subscription\"\n },\n disconnect_reasons: {\n unauthorized: \"unauthorized\",\n invalid_request: \"invalid_request\",\n server_restart: \"server_restart\",\n remote: \"remote\"\n },\n default_mount_path: \"/cable\",\n protocols: [ \"actioncable-v1-json\", \"actioncable-unsupported\" ]\n};\n\nconst {message_types: message_types, protocols: protocols} = INTERNAL;\n\nconst supportedProtocols = protocols.slice(0, protocols.length - 1);\n\nconst indexOf = [].indexOf;\n\nclass Connection {\n constructor(consumer) {\n this.open = this.open.bind(this);\n this.consumer = consumer;\n this.subscriptions = this.consumer.subscriptions;\n this.monitor = new ConnectionMonitor(this);\n this.disconnected = true;\n }\n send(data) {\n if (this.isOpen()) {\n this.webSocket.send(JSON.stringify(data));\n return true;\n } else {\n return false;\n }\n }\n open() {\n if (this.isActive()) {\n logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);\n return false;\n } else {\n const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];\n logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);\n if (this.webSocket) {\n this.uninstallEventHandlers();\n }\n this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);\n this.installEventHandlers();\n this.monitor.start();\n return true;\n }\n }\n close({allowReconnect: allowReconnect} = {\n allowReconnect: true\n }) {\n if (!allowReconnect) {\n this.monitor.stop();\n }\n if (this.isOpen()) {\n return this.webSocket.close();\n }\n }\n reopen() {\n logger.log(`Reopening WebSocket, current state is ${this.getState()}`);\n if (this.isActive()) {\n try {\n return this.close();\n } catch (error) {\n logger.log(\"Failed to reopen WebSocket\", error);\n } finally {\n logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);\n setTimeout(this.open, this.constructor.reopenDelay);\n }\n } else {\n return this.open();\n }\n }\n getProtocol() {\n if (this.webSocket) {\n return this.webSocket.protocol;\n }\n }\n isOpen() {\n return this.isState(\"open\");\n }\n isActive() {\n return this.isState(\"open\", \"connecting\");\n }\n triedToReconnect() {\n return this.monitor.reconnectAttempts > 0;\n }\n isProtocolSupported() {\n return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;\n }\n isState(...states) {\n return indexOf.call(states, this.getState()) >= 0;\n }\n getState() {\n if (this.webSocket) {\n for (let state in adapters.WebSocket) {\n if (adapters.WebSocket[state] === this.webSocket.readyState) {\n return state.toLowerCase();\n }\n }\n }\n return null;\n }\n installEventHandlers() {\n for (let eventName in this.events) {\n const handler = this.events[eventName].bind(this);\n this.webSocket[`on${eventName}`] = handler;\n }\n }\n uninstallEventHandlers() {\n for (let eventName in this.events) {\n this.webSocket[`on${eventName}`] = function() {};\n }\n }\n}\n\nConnection.reopenDelay = 500;\n\nConnection.prototype.events = {\n message(event) {\n if (!this.isProtocolSupported()) {\n return;\n }\n const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);\n this.monitor.recordMessage();\n switch (type) {\n case message_types.welcome:\n if (this.triedToReconnect()) {\n this.reconnectAttempted = true;\n }\n this.monitor.recordConnect();\n return this.subscriptions.reload();\n\n case message_types.disconnect:\n logger.log(`Disconnecting. Reason: ${reason}`);\n return this.close({\n allowReconnect: reconnect\n });\n\n case message_types.ping:\n return null;\n\n case message_types.confirmation:\n this.subscriptions.confirmSubscription(identifier);\n if (this.reconnectAttempted) {\n this.reconnectAttempted = false;\n return this.subscriptions.notify(identifier, \"connected\", {\n reconnected: true\n });\n } else {\n return this.subscriptions.notify(identifier, \"connected\", {\n reconnected: false\n });\n }\n\n case message_types.rejection:\n return this.subscriptions.reject(identifier);\n\n default:\n return this.subscriptions.notify(identifier, \"received\", message);\n }\n },\n open() {\n logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);\n this.disconnected = false;\n if (!this.isProtocolSupported()) {\n logger.log(\"Protocol is unsupported. Stopping monitor and disconnecting.\");\n return this.close({\n allowReconnect: false\n });\n }\n },\n close(event) {\n logger.log(\"WebSocket onclose event\");\n if (this.disconnected) {\n return;\n }\n this.disconnected = true;\n this.monitor.recordDisconnect();\n return this.subscriptions.notifyAll(\"disconnected\", {\n willAttemptReconnect: this.monitor.isRunning()\n });\n },\n error() {\n logger.log(\"WebSocket onerror event\");\n }\n};\n\nconst extend = function(object, properties) {\n if (properties != null) {\n for (let key in properties) {\n const value = properties[key];\n object[key] = value;\n }\n }\n return object;\n};\n\nclass Subscription {\n constructor(consumer, params = {}, mixin) {\n this.consumer = consumer;\n this.identifier = JSON.stringify(params);\n extend(this, mixin);\n }\n perform(action, data = {}) {\n data.action = action;\n return this.send(data);\n }\n send(data) {\n return this.consumer.send({\n command: \"message\",\n identifier: this.identifier,\n data: JSON.stringify(data)\n });\n }\n unsubscribe() {\n return this.consumer.subscriptions.remove(this);\n }\n}\n\nclass SubscriptionGuarantor {\n constructor(subscriptions) {\n this.subscriptions = subscriptions;\n this.pendingSubscriptions = [];\n }\n guarantee(subscription) {\n if (this.pendingSubscriptions.indexOf(subscription) == -1) {\n logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`);\n this.pendingSubscriptions.push(subscription);\n } else {\n logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`);\n }\n this.startGuaranteeing();\n }\n forget(subscription) {\n logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`);\n this.pendingSubscriptions = this.pendingSubscriptions.filter((s => s !== subscription));\n }\n startGuaranteeing() {\n this.stopGuaranteeing();\n this.retrySubscribing();\n }\n stopGuaranteeing() {\n clearTimeout(this.retryTimeout);\n }\n retrySubscribing() {\n this.retryTimeout = setTimeout((() => {\n if (this.subscriptions && typeof this.subscriptions.subscribe === \"function\") {\n this.pendingSubscriptions.map((subscription => {\n logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`);\n this.subscriptions.subscribe(subscription);\n }));\n }\n }), 500);\n }\n}\n\nclass Subscriptions {\n constructor(consumer) {\n this.consumer = consumer;\n this.guarantor = new SubscriptionGuarantor(this);\n this.subscriptions = [];\n }\n create(channelName, mixin) {\n const channel = channelName;\n const params = typeof channel === \"object\" ? channel : {\n channel: channel\n };\n const subscription = new Subscription(this.consumer, params, mixin);\n return this.add(subscription);\n }\n add(subscription) {\n this.subscriptions.push(subscription);\n this.consumer.ensureActiveConnection();\n this.notify(subscription, \"initialized\");\n this.subscribe(subscription);\n return subscription;\n }\n remove(subscription) {\n this.forget(subscription);\n if (!this.findAll(subscription.identifier).length) {\n this.sendCommand(subscription, \"unsubscribe\");\n }\n return subscription;\n }\n reject(identifier) {\n return this.findAll(identifier).map((subscription => {\n this.forget(subscription);\n this.notify(subscription, \"rejected\");\n return subscription;\n }));\n }\n forget(subscription) {\n this.guarantor.forget(subscription);\n this.subscriptions = this.subscriptions.filter((s => s !== subscription));\n return subscription;\n }\n findAll(identifier) {\n return this.subscriptions.filter((s => s.identifier === identifier));\n }\n reload() {\n return this.subscriptions.map((subscription => this.subscribe(subscription)));\n }\n notifyAll(callbackName, ...args) {\n return this.subscriptions.map((subscription => this.notify(subscription, callbackName, ...args)));\n }\n notify(subscription, callbackName, ...args) {\n let subscriptions;\n if (typeof subscription === \"string\") {\n subscriptions = this.findAll(subscription);\n } else {\n subscriptions = [ subscription ];\n }\n return subscriptions.map((subscription => typeof subscription[callbackName] === \"function\" ? subscription[callbackName](...args) : undefined));\n }\n subscribe(subscription) {\n if (this.sendCommand(subscription, \"subscribe\")) {\n this.guarantor.guarantee(subscription);\n }\n }\n confirmSubscription(identifier) {\n logger.log(`Subscription confirmed ${identifier}`);\n this.findAll(identifier).map((subscription => this.guarantor.forget(subscription)));\n }\n sendCommand(subscription, command) {\n const {identifier: identifier} = subscription;\n return this.consumer.send({\n command: command,\n identifier: identifier\n });\n }\n}\n\nclass Consumer {\n constructor(url) {\n this._url = url;\n this.subscriptions = new Subscriptions(this);\n this.connection = new Connection(this);\n this.subprotocols = [];\n }\n get url() {\n return createWebSocketURL(this._url);\n }\n send(data) {\n return this.connection.send(data);\n }\n connect() {\n return this.connection.open();\n }\n disconnect() {\n return this.connection.close({\n allowReconnect: false\n });\n }\n ensureActiveConnection() {\n if (!this.connection.isActive()) {\n return this.connection.open();\n }\n }\n addSubProtocol(subprotocol) {\n this.subprotocols = [ ...this.subprotocols, subprotocol ];\n }\n}\n\nfunction createWebSocketURL(url) {\n if (typeof url === \"function\") {\n url = url();\n }\n if (url && !/^wss?:/i.test(url)) {\n const a = document.createElement(\"a\");\n a.href = url;\n a.href = a.href;\n a.protocol = a.protocol.replace(\"http\", \"ws\");\n return a.href;\n } else {\n return url;\n }\n}\n\nfunction createConsumer(url = getConfig(\"url\") || INTERNAL.default_mount_path) {\n return new Consumer(url);\n}\n\nfunction getConfig(name) {\n const element = document.head.querySelector(`meta[name='action-cable-${name}']`);\n if (element) {\n return element.getAttribute(\"content\");\n }\n}\n\nexport { Connection, ConnectionMonitor, Consumer, INTERNAL, Subscription, SubscriptionGuarantor, Subscriptions, adapters, createConsumer, createWebSocketURL, getConfig, logger };\n","import { createConsumer } from \"@rails/actioncable\"\n\nexport default createConsumer(\"/hotwire-spark\")\n","export function assetNameFromPath(path) {\n return path.split(\"/\").pop().split(\".\")[0]\n}\n\nexport function pathWithoutAssetDigest(path) {\n return path.replace(/-[a-z0-9]+\\.(\\w+)(\\?.*)?$/, \".$1\")\n}\n\nexport function urlWithParams(urlString, params) {\n const url = new URL(urlString, window.location.origin)\n Object.entries(params).forEach(([ key, value ]) => {\n url.searchParams.set(key, value)\n })\n return url.toString()\n}\n\nexport function cacheBustedUrl(urlString) {\n return urlWithParams(urlString, { reload: Date.now() })\n}\n\nexport async function reloadHtmlDocument() {\n let currentUrl = cacheBustedUrl(urlWithParams(window.location.href, { hotwire_spark: \"true\" }))\n const response = await fetch(currentUrl, { headers: { \"Accept\": \"text/html\" }})\n\n if (!response.ok) {\n throw new Error(`${response.status} when fetching ${currentUrl}`)\n }\n\n const fetchedHTML = await response.text()\n const parser = new DOMParser()\n return parser.parseFromString(fetchedHTML, \"text/html\")\n}\n\nexport function getConfigurationProperty(name) {\n return document.querySelector(`meta[name=\"hotwire-spark:${name}\"]`)?.content\n}\n\n","// base IIFE to define idiomorph\nvar Idiomorph = (function () {\n 'use strict';\n\n //=============================================================================\n // AND NOW IT BEGINS...\n //=============================================================================\n let EMPTY_SET = new Set();\n\n // default configuration values, updatable by users now\n let defaults = {\n morphStyle: \"outerHTML\",\n callbacks : {\n beforeNodeAdded: noOp,\n afterNodeAdded: noOp,\n beforeNodeMorphed: noOp,\n afterNodeMorphed: noOp,\n beforeNodeRemoved: noOp,\n afterNodeRemoved: noOp,\n beforeAttributeUpdated: noOp,\n\n },\n head: {\n style: 'merge',\n shouldPreserve: function (elt) {\n return elt.getAttribute(\"im-preserve\") === \"true\";\n },\n shouldReAppend: function (elt) {\n return elt.getAttribute(\"im-re-append\") === \"true\";\n },\n shouldRemove: noOp,\n afterHeadMorphed: noOp,\n }\n };\n\n //=============================================================================\n // Core Morphing Algorithm - morph, morphNormalizedContent, morphOldNodeTo, morphChildren\n //=============================================================================\n function morph(oldNode, newContent, config = {}) {\n\n if (oldNode instanceof Document) {\n oldNode = oldNode.documentElement;\n }\n\n if (typeof newContent === 'string') {\n newContent = parseContent(newContent);\n }\n\n let normalizedContent = normalizeContent(newContent);\n\n let ctx = createMorphContext(oldNode, normalizedContent, config);\n\n return morphNormalizedContent(oldNode, normalizedContent, ctx);\n }\n\n function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {\n if (ctx.head.block) {\n let oldHead = oldNode.querySelector('head');\n let newHead = normalizedNewContent.querySelector('head');\n if (oldHead && newHead) {\n let promises = handleHeadElement(newHead, oldHead, ctx);\n // when head promises resolve, call morph again, ignoring the head tag\n Promise.all(promises).then(function () {\n morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, {\n head: {\n block: false,\n ignore: true\n }\n }));\n });\n return;\n }\n }\n\n if (ctx.morphStyle === \"innerHTML\") {\n\n // innerHTML, so we are only updating the children\n morphChildren(normalizedNewContent, oldNode, ctx);\n return oldNode.children;\n\n } else if (ctx.morphStyle === \"outerHTML\" || ctx.morphStyle == null) {\n // otherwise find the best element match in the new content, morph that, and merge its siblings\n // into either side of the best match\n let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);\n\n // stash the siblings that will need to be inserted on either side of the best match\n let previousSibling = bestMatch?.previousSibling;\n let nextSibling = bestMatch?.nextSibling;\n\n // morph it\n let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);\n\n if (bestMatch) {\n // if there was a best match, merge the siblings in too and return the\n // whole bunch\n return insertSiblings(previousSibling, morphedNode, nextSibling);\n } else {\n // otherwise nothing was added to the DOM\n return []\n }\n } else {\n throw \"Do not understand how to morph style \" + ctx.morphStyle;\n }\n }\n\n\n /**\n * @param possibleActiveElement\n * @param ctx\n * @returns {boolean}\n */\n function ignoreValueOfActiveElement(possibleActiveElement, ctx) {\n return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement;\n }\n\n /**\n * @param oldNode root node to merge content into\n * @param newContent new content to merge\n * @param ctx the merge context\n * @returns {Element} the element that ended up in the DOM\n */\n function morphOldNodeTo(oldNode, newContent, ctx) {\n if (ctx.ignoreActive && oldNode === document.activeElement) {\n // don't morph focused element\n } else if (newContent == null) {\n if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;\n\n oldNode.remove();\n ctx.callbacks.afterNodeRemoved(oldNode);\n return null;\n } else if (!isSoftMatch(oldNode, newContent)) {\n if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;\n if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode;\n\n oldNode.parentElement.replaceChild(newContent, oldNode);\n ctx.callbacks.afterNodeAdded(newContent);\n ctx.callbacks.afterNodeRemoved(oldNode);\n return newContent;\n } else {\n if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode;\n\n if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) {\n // ignore the head element\n } else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== \"morph\") {\n handleHeadElement(newContent, oldNode, ctx);\n } else {\n syncNodeFrom(newContent, oldNode, ctx);\n if (!ignoreValueOfActiveElement(oldNode, ctx)) {\n morphChildren(newContent, oldNode, ctx);\n }\n }\n ctx.callbacks.afterNodeMorphed(oldNode, newContent);\n return oldNode;\n }\n }\n\n /**\n * This is the core algorithm for matching up children. The idea is to use id sets to try to match up\n * nodes as faithfully as possible. We greedily match, which allows us to keep the algorithm fast, but\n * by using id sets, we are able to better match up with content deeper in the DOM.\n *\n * Basic algorithm is, for each node in the new content:\n *\n * - if we have reached the end of the old parent, append the new content\n * - if the new content has an id set match with the current insertion point, morph\n * - search for an id set match\n * - if id set match found, morph\n * - otherwise search for a \"soft\" match\n * - if a soft match is found, morph\n * - otherwise, prepend the new node before the current insertion point\n *\n * The two search algorithms terminate if competing node matches appear to outweigh what can be achieved\n * with the current node. See findIdSetMatch() and findSoftMatch() for details.\n *\n * @param {Element} newParent the parent element of the new content\n * @param {Element } oldParent the old content that we are merging the new content into\n * @param ctx the merge context\n */\n function morphChildren(newParent, oldParent, ctx) {\n\n let nextNewChild = newParent.firstChild;\n let insertionPoint = oldParent.firstChild;\n let newChild;\n\n // run through all the new content\n while (nextNewChild) {\n\n newChild = nextNewChild;\n nextNewChild = newChild.nextSibling;\n\n // if we are at the end of the exiting parent's children, just append\n if (insertionPoint == null) {\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;\n\n oldParent.appendChild(newChild);\n ctx.callbacks.afterNodeAdded(newChild);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // if the current node has an id set match then morph\n if (isIdSetMatch(newChild, insertionPoint, ctx)) {\n morphOldNodeTo(insertionPoint, newChild, ctx);\n insertionPoint = insertionPoint.nextSibling;\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // otherwise search forward in the existing old children for an id set match\n let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);\n\n // if we found a potential match, remove the nodes until that point and morph\n if (idSetMatch) {\n insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);\n morphOldNodeTo(idSetMatch, newChild, ctx);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // no id set match found, so scan forward for a soft match for the current node\n let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);\n\n // if we found a soft match for the current node, morph\n if (softMatch) {\n insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);\n morphOldNodeTo(softMatch, newChild, ctx);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // abandon all hope of morphing, just insert the new child before the insertion point\n // and move on\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;\n\n oldParent.insertBefore(newChild, insertionPoint);\n ctx.callbacks.afterNodeAdded(newChild);\n removeIdsFromConsideration(ctx, newChild);\n }\n\n // remove any remaining old nodes that didn't match up with new content\n while (insertionPoint !== null) {\n\n let tempNode = insertionPoint;\n insertionPoint = insertionPoint.nextSibling;\n removeNode(tempNode, ctx);\n }\n }\n\n //=============================================================================\n // Attribute Syncing Code\n //=============================================================================\n\n /**\n * @param attr {String} the attribute to be mutated\n * @param to {Element} the element that is going to be updated\n * @param updateType {(\"update\"|\"remove\")}\n * @param ctx the merge context\n * @returns {boolean} true if the attribute should be ignored, false otherwise\n */\n function ignoreAttribute(attr, to, updateType, ctx) {\n if(attr === 'value' && ctx.ignoreActiveValue && to === document.activeElement){\n return true;\n }\n return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;\n }\n\n /**\n * syncs a given node with another node, copying over all attributes and\n * inner element state from the 'from' node to the 'to' node\n *\n * @param {Element} from the element to copy attributes & state from\n * @param {Element} to the element to copy attributes & state to\n * @param ctx the merge context\n */\n function syncNodeFrom(from, to, ctx) {\n let type = from.nodeType\n\n // if is an element type, sync the attributes from the\n // new node into the new node\n if (type === 1 /* element type */) {\n const fromAttributes = from.attributes;\n const toAttributes = to.attributes;\n for (const fromAttribute of fromAttributes) {\n if (ignoreAttribute(fromAttribute.name, to, 'update', ctx)) {\n continue;\n }\n if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) {\n to.setAttribute(fromAttribute.name, fromAttribute.value);\n }\n }\n // iterate backwards to avoid skipping over items when a delete occurs\n for (let i = toAttributes.length - 1; 0 <= i; i--) {\n const toAttribute = toAttributes[i];\n if (ignoreAttribute(toAttribute.name, to, 'remove', ctx)) {\n continue;\n }\n if (!from.hasAttribute(toAttribute.name)) {\n to.removeAttribute(toAttribute.name);\n }\n }\n }\n\n // sync text nodes\n if (type === 8 /* comment */ || type === 3 /* text */) {\n if (to.nodeValue !== from.nodeValue) {\n to.nodeValue = from.nodeValue;\n }\n }\n\n if (!ignoreValueOfActiveElement(to, ctx)) {\n // sync input values\n syncInputValue(from, to, ctx);\n }\n }\n\n /**\n * @param from {Element} element to sync the value from\n * @param to {Element} element to sync the value to\n * @param attributeName {String} the attribute name\n * @param ctx the merge context\n */\n function syncBooleanAttribute(from, to, attributeName, ctx) {\n if (from[attributeName] !== to[attributeName]) {\n let ignoreUpdate = ignoreAttribute(attributeName, to, 'update', ctx);\n if (!ignoreUpdate) {\n to[attributeName] = from[attributeName];\n }\n if (from[attributeName]) {\n if (!ignoreUpdate) {\n to.setAttribute(attributeName, from[attributeName]);\n }\n } else {\n if (!ignoreAttribute(attributeName, to, 'remove', ctx)) {\n to.removeAttribute(attributeName);\n }\n }\n }\n }\n\n /**\n * NB: many bothans died to bring us information:\n *\n * https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js\n * https://github.com/choojs/nanomorph/blob/master/lib/morph.jsL113\n *\n * @param from {Element} the element to sync the input value from\n * @param to {Element} the element to sync the input value to\n * @param ctx the merge context\n */\n function syncInputValue(from, to, ctx) {\n if (from instanceof HTMLInputElement &&\n to instanceof HTMLInputElement &&\n from.type !== 'file') {\n\n let fromValue = from.value;\n let toValue = to.value;\n\n // sync boolean attributes\n syncBooleanAttribute(from, to, 'checked', ctx);\n syncBooleanAttribute(from, to, 'disabled', ctx);\n\n if (!from.hasAttribute('value')) {\n if (!ignoreAttribute('value', to, 'remove', ctx)) {\n to.value = '';\n to.removeAttribute('value');\n }\n } else if (fromValue !== toValue) {\n if (!ignoreAttribute('value', to, 'update', ctx)) {\n to.setAttribute('value', fromValue);\n to.value = fromValue;\n }\n }\n } else if (from instanceof HTMLOptionElement) {\n syncBooleanAttribute(from, to, 'selected', ctx)\n } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {\n let fromValue = from.value;\n let toValue = to.value;\n if (ignoreAttribute('value', to, 'update', ctx)) {\n return;\n }\n if (fromValue !== toValue) {\n to.value = fromValue;\n }\n if (to.firstChild && to.firstChild.nodeValue !== fromValue) {\n to.firstChild.nodeValue = fromValue\n }\n }\n }\n\n //=============================================================================\n // the HEAD tag can be handled specially, either w/ a 'merge' or 'append' style\n //=============================================================================\n function handleHeadElement(newHeadTag, currentHead, ctx) {\n\n let added = []\n let removed = []\n let preserved = []\n let nodesToAppend = []\n\n let headMergeStyle = ctx.head.style;\n\n // put all new head elements into a Map, by their outerHTML\n let srcToNewHeadNodes = new Map();\n for (const newHeadChild of newHeadTag.children) {\n srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);\n }\n\n // for each elt in the current head\n for (const currentHeadElt of currentHead.children) {\n\n // If the current head element is in the map\n let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);\n let isReAppended = ctx.head.shouldReAppend(currentHeadElt);\n let isPreserved = ctx.head.shouldPreserve(currentHeadElt);\n if (inNewContent || isPreserved) {\n if (isReAppended) {\n // remove the current version and let the new version replace it and re-execute\n removed.push(currentHeadElt);\n } else {\n // this element already exists and should not be re-appended, so remove it from\n // the new content map, preserving it in the DOM\n srcToNewHeadNodes.delete(currentHeadElt.outerHTML);\n preserved.push(currentHeadElt);\n }\n } else {\n if (headMergeStyle === \"append\") {\n // we are appending and this existing element is not new content\n // so if and only if it is marked for re-append do we do anything\n if (isReAppended) {\n removed.push(currentHeadElt);\n nodesToAppend.push(currentHeadElt);\n }\n } else {\n // if this is a merge, we remove this content since it is not in the new head\n if (ctx.head.shouldRemove(currentHeadElt) !== false) {\n removed.push(currentHeadElt);\n }\n }\n }\n }\n\n // Push the remaining new head elements in the Map into the\n // nodes to append to the head tag\n nodesToAppend.push(...srcToNewHeadNodes.values());\n log(\"to append: \", nodesToAppend);\n\n let promises = [];\n for (const newNode of nodesToAppend) {\n log(\"adding: \", newNode);\n let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;\n log(newElt);\n if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {\n if (newElt.href || newElt.src) {\n let resolve = null;\n let promise = new Promise(function (_resolve) {\n resolve = _resolve;\n });\n newElt.addEventListener('load', function () {\n resolve();\n });\n promises.push(promise);\n }\n currentHead.appendChild(newElt);\n ctx.callbacks.afterNodeAdded(newElt);\n added.push(newElt);\n }\n }\n\n // remove all removed elements, after we have appended the new elements to avoid\n // additional network requests for things like style sheets\n for (const removedElement of removed) {\n if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {\n currentHead.removeChild(removedElement);\n ctx.callbacks.afterNodeRemoved(removedElement);\n }\n }\n\n ctx.head.afterHeadMorphed(currentHead, {added: added, kept: preserved, removed: removed});\n return promises;\n }\n\n //=============================================================================\n // Misc\n //=============================================================================\n\n function log() {\n //console.log(arguments);\n }\n\n function noOp() {\n }\n\n /*\n Deep merges the config object and the Idiomoroph.defaults object to\n produce a final configuration object\n */\n function mergeDefaults(config) {\n let finalConfig = {};\n // copy top level stuff into final config\n Object.assign(finalConfig, defaults);\n Object.assign(finalConfig, config);\n\n // copy callbacks into final config (do this to deep merge the callbacks)\n finalConfig.callbacks = {};\n Object.assign(finalConfig.callbacks, defaults.callbacks);\n Object.assign(finalConfig.callbacks, config.callbacks);\n\n // copy head config into final config (do this to deep merge the head)\n finalConfig.head = {};\n Object.assign(finalConfig.head, defaults.head);\n Object.assign(finalConfig.head, config.head);\n return finalConfig;\n }\n\n function createMorphContext(oldNode, newContent, config) {\n config = mergeDefaults(config);\n return {\n target: oldNode,\n newContent: newContent,\n config: config,\n morphStyle: config.morphStyle,\n ignoreActive: config.ignoreActive,\n ignoreActiveValue: config.ignoreActiveValue,\n idMap: createIdMap(oldNode, newContent),\n deadIds: new Set(),\n callbacks: config.callbacks,\n head: config.head\n }\n }\n\n function isIdSetMatch(node1, node2, ctx) {\n if (node1 == null || node2 == null) {\n return false;\n }\n if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) {\n if (node1.id !== \"\" && node1.id === node2.id) {\n return true;\n } else {\n return getIdIntersectionCount(ctx, node1, node2) > 0;\n }\n }\n return false;\n }\n\n function isSoftMatch(node1, node2) {\n if (node1 == null || node2 == null) {\n return false;\n }\n return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName\n }\n\n function removeNodesBetween(startInclusive, endExclusive, ctx) {\n while (startInclusive !== endExclusive) {\n let tempNode = startInclusive;\n startInclusive = startInclusive.nextSibling;\n removeNode(tempNode, ctx);\n }\n removeIdsFromConsideration(ctx, endExclusive);\n return endExclusive.nextSibling;\n }\n\n //=============================================================================\n // Scans forward from the insertionPoint in the old parent looking for a potential id match\n // for the newChild. We stop if we find a potential id match for the new child OR\n // if the number of potential id matches we are discarding is greater than the\n // potential id matches for the new child\n //=============================================================================\n function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {\n\n // max id matches we are willing to discard in our search\n let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);\n\n let potentialMatch = null;\n\n // only search forward if there is a possibility of an id match\n if (newChildPotentialIdCount > 0) {\n let potentialMatch = insertionPoint;\n // if there is a possibility of an id match, scan forward\n // keep track of the potential id match count we are discarding (the\n // newChildPotentialIdCount must be greater than this to make it likely\n // worth it)\n let otherMatchCount = 0;\n while (potentialMatch != null) {\n\n // If we have an id match, return the current potential match\n if (isIdSetMatch(newChild, potentialMatch, ctx)) {\n return potentialMatch;\n }\n\n // computer the other potential matches of this new content\n otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent);\n if (otherMatchCount > newChildPotentialIdCount) {\n // if we have more potential id matches in _other_ content, we\n // do not have a good candidate for an id match, so return null\n return null;\n }\n\n // advanced to the next old content child\n potentialMatch = potentialMatch.nextSibling;\n }\n }\n return potentialMatch;\n }\n\n //=============================================================================\n // Scans forward from the insertionPoint in the old parent looking for a potential soft match\n // for the newChild. We stop if we find a potential soft match for the new child OR\n // if we find a potential id match in the old parents children OR if we find two\n // potential soft matches for the next two pieces of new content\n //=============================================================================\n function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {\n\n let potentialSoftMatch = insertionPoint;\n let nextSibling = newChild.nextSibling;\n let siblingSoftMatchCount = 0;\n\n while (potentialSoftMatch != null) {\n\n if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {\n // the current potential soft match has a potential id set match with the remaining new\n // content so bail out of looking\n return null;\n }\n\n // if we have a soft match with the current node, return it\n if (isSoftMatch(newChild, potentialSoftMatch)) {\n return potentialSoftMatch;\n }\n\n if (isSoftMatch(nextSibling, potentialSoftMatch)) {\n // the next new node has a soft match with this node, so\n // increment the count of future soft matches\n siblingSoftMatchCount++;\n nextSibling = nextSibling.nextSibling;\n\n // If there are two future soft matches, bail to allow the siblings to soft match\n // so that we don't consume future soft matches for the sake of the current node\n if (siblingSoftMatchCount >= 2) {\n return null;\n }\n }\n\n // advanced to the next old content child\n potentialSoftMatch = potentialSoftMatch.nextSibling;\n }\n\n return potentialSoftMatch;\n }\n\n function parseContent(newContent) {\n let parser = new DOMParser();\n\n // remove svgs to avoid false-positive matches on head, etc.\n let contentWithSvgsRemoved = newContent.replace(/<svg(\\s[^>]*>|>)([\\s\\S]*?)<\\/svg>/gim, '');\n\n // if the newContent contains a html, head or body tag, we can simply parse it w/o wrapping\n if (contentWithSvgsRemoved.match(/<\\/html>/) || contentWithSvgsRemoved.match(/<\\/head>/) || contentWithSvgsRemoved.match(/<\\/body>/)) {\n let content = parser.parseFromString(newContent, \"text/html\");\n // if it is a full HTML document, return the document itself as the parent container\n if (contentWithSvgsRemoved.match(/<\\/html>/)) {\n content.generatedByIdiomorph = true;\n return content;\n } else {\n // otherwise return the html element as the parent container\n let htmlElement = content.firstChild;\n if (htmlElement) {\n htmlElement.generatedByIdiomorph = true;\n return htmlElement;\n } else {\n return null;\n }\n }\n } else {\n // if it is partial HTML, wrap it in a template tag to provide a parent element and also to help\n // deal with touchy tags like tr, tbody, etc.\n let responseDoc = parser.parseFromString(\"<body><template>\" + newContent + \"</template></body>\", \"text/html\");\n let content = responseDoc.body.querySelector('template').content;\n content.generatedByIdiomorph = true;\n return content\n }\n }\n\n function normalizeContent(newContent) {\n if (newContent == null) {\n // noinspection UnnecessaryLocalVariableJS\n const dummyParent = document.createElement('div');\n return dummyParent;\n } else if (newContent.generatedByIdiomorph) {\n // the template tag created by idiomorph parsing can serve as a dummy parent\n return newContent;\n } else if (newContent instanceof Node) {\n // a single node is added as a child to a dummy parent\n const dummyParent = document.createElement('div');\n dummyParent.append(newContent);\n return dummyParent;\n } else {\n // all nodes in the array or HTMLElement collection are consolidated under\n // a single dummy parent element\n const dummyParent = document.createElement('div');\n for (const elt of [...newContent]) {\n dummyParent.append(elt);\n }\n return dummyParent;\n }\n }\n\n function insertSiblings(previousSibling, morphedNode, nextSibling) {\n let stack = []\n let added = []\n while (previousSibling != null) {\n stack.push(previousSibling);\n previousSibling = previousSibling.previousSibling;\n }\n while (stack.length > 0) {\n let node = stack.pop();\n added.push(node); // push added preceding siblings on in order and insert\n morphedNode.parentElement.insertBefore(node, morphedNode);\n }\n added.push(morphedNode);\n while (nextSibling != null) {\n stack.push(nextSibling);\n added.push(nextSibling); // here we are going in order, so push on as we scan, rather than add\n nextSibling = nextSibling.nextSibling;\n }\n while (stack.length > 0) {\n morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);\n }\n return added;\n }\n\n function findBestNodeMatch(newContent, oldNode, ctx) {\n let currentElement;\n currentElement = newContent.firstChild;\n let bestElement = currentElement;\n let score = 0;\n while (currentElement) {\n let newScore = scoreElement(currentElement, oldNode, ctx);\n if (newScore > score) {\n bestElement = currentElement;\n score = newScore;\n }\n currentElement = currentElement.nextSibling;\n }\n return bestElement;\n }\n\n function scoreElement(node1, node2, ctx) {\n if (isSoftMatch(node1, node2)) {\n return .5 + getIdIntersectionCount(ctx, node1, node2);\n }\n return 0;\n }\n\n function removeNode(tempNode, ctx) {\n removeIdsFromConsideration(ctx, tempNode)\n if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;\n\n tempNode.remove();\n ctx.callbacks.afterNodeRemoved(tempNode);\n }\n\n //=============================================================================\n // ID Set Functions\n //=============================================================================\n\n function isIdInConsideration(ctx, id) {\n return !ctx.deadIds.has(id);\n }\n\n function idIsWithinNode(ctx, id, targetNode) {\n let idSet = ctx.idMap.get(targetNode) || EMPTY_SET;\n return idSet.has(id);\n }\n\n function removeIdsFromConsideration(ctx, node) {\n let idSet = ctx.idMap.get(node) || EMPTY_SET;\n for (const id of idSet) {\n ctx.deadIds.add(id);\n }\n }\n\n function getIdIntersectionCount(ctx, node1, node2) {\n let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;\n let matchCount = 0;\n for (const id of sourceSet) {\n // a potential match is an id in the source and potentialIdsSet, but\n // that has not already been merged into the DOM\n if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) {\n ++matchCount;\n }\n }\n return matchCount;\n }\n\n /**\n * A bottom up algorithm that finds all elements with ids inside of the node\n * argument and populates id sets for those nodes and all their parents, generating\n * a set of ids contained within all nodes for the entire hierarchy in the DOM\n *\n * @param node {Element}\n * @param {Map<Node, Set<String>>} idMap\n */\n function populateIdMapForNode(node, idMap) {\n let nodeParent = node.parentElement;\n // find all elements with an id property\n let idElements = node.querySelectorAll('[id]');\n for (const elt of idElements) {\n let current = elt;\n // walk up the parent hierarchy of that element, adding the id\n // of element to the parent's id set\n while (current !== nodeParent && current != null) {\n let idSet = idMap.get(current);\n // if the id set doesn't exist, create it and insert it in the map\n if (idSet == null) {\n idSet = new Set();\n idMap.set(current, idSet);\n }\n idSet.add(elt.id);\n current = current.parentElement;\n }\n }\n }\n\n /**\n * This function computes a map of nodes to all ids contained within that node (inclusive of the\n * node). This map can be used to ask if two nodes have intersecting sets of ids, which allows\n * for a looser definition of \"matching\" than tradition id matching, and allows child nodes\n * to contribute to a parent nodes matching.\n *\n * @param {Element} oldContent the old content that will be morphed\n * @param {Element} newContent the new content to morph to\n * @returns {Map<Node, Set<String>>} a map of nodes to id sets for the\n */\n function createIdMap(oldContent, newContent) {\n let idMap = new Map();\n populateIdMapForNode(oldContent, idMap);\n populateIdMapForNode(newContent, idMap);\n return idMap;\n }\n\n //=============================================================================\n // This is what ends up becoming the Idiomorph global object\n //=============================================================================\n return {\n morph,\n defaults\n }\n })();\n\nexport {Idiomorph};\n","import HotwireSpark from \"./index.js\"\n\nexport function log(...args) {\n if (HotwireSpark.config.loggingEnabled) {\n console.log(`[hotwire_spark]`, ...args)\n }\n}\n\n","import { log } from \"../logger.js\"\nimport { cacheBustedUrl, reloadHtmlDocument } from \"../helpers.js\"\n\nexport class StimulusReloader {\n static async reload(changedFilePath) {\n const document = await reloadHtmlDocument()\n return new StimulusReloader(document, changedFilePath).reload()\n }\n\n static async reloadAll() {\n Stimulus.controllers.forEach(controller => {\n Stimulus.unload(controller.identifier)\n Stimulus.register(controller.identifier, controller.constructor)\n })\n\n return Promise.resolve()\n }\n\n constructor(document, changedFilePath) {\n this.document = document\n this.changedFilePath = changedFilePath\n this.application = window.Stimulus\n }\n\n async reload() {\n log(\"Reload Stimulus controllers...\")\n\n this.application.stop()\n\n await this.#reloadChangedStimulusControllers()\n this.#unloadDeletedStimulusControllers()\n\n this.application.start()\n }\n\n async #reloadChangedStimulusControllers() {\n await Promise.all(\n this.#stimulusControllerPathsToReload.map(async moduleName => this.#reloadStimulusController(moduleName))\n )\n }\n\n get #stimulusControllerPathsToReload() {\n this.controllerPathsToReload = this.controllerPathsToReload || this.#stimulusControllerPaths.filter(path => this.#shouldReloadController(path))\n return this.controllerPathsToReload\n }\n\n get #stimulusControllerPaths() {\n return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith(\"_controller\"))\n }\n\n #shouldReloadController(path) {\n return this.#extractControllerName(path) === this.#changedControllerIdentifier\n }\n\n get #changedControllerIdentifier() {\n this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.changedFilePath)\n return this.changedControllerIdentifier\n }\n\n get #stimulusPathsByModule() {\n this.pathsByModule = this.pathsByModule || this.#parseImportmapJson()\n return this.pathsByModule\n }\n\n #parseImportmapJson() {\n const importmapScript = this.document.querySelector(\"script[type=importmap]\")\n return JSON.parse(importmapScript.text).imports\n }\n\n async #reloadStimulusController(moduleName) {\n log(`\\t${moduleName}`)\n\n const controllerName = this.#extractControllerName(moduleName)\n const path = cacheBustedUrl(this.#pathForModuleName(moduleName))\n\n const module = await import(path)\n\n this.#registerController(controllerName, module)\n }\n\n #unloadDeletedStimulusControllers() {\n this.#controllersToUnload.forEach(controller => this.#deregisterController(controller.identifier))\n }\n\n get #controllersToUnload() {\n if (this.#didChangeTriggerAReload) {\n return []\n } else {\n return this.application.controllers.filter(controller => this.#changedControllerIdentifier === controller.identifier)\n }\n }\n\n get #didChangeTriggerAReload() {\n return this.#stimulusControllerPathsToReload.length > 0\n }\n\n #pathForModuleName(moduleName) {\n return this.#stimulusPathsByModule[moduleName]\n }\n\n #extractControllerName(path) {\n return path\n .replace(/^\\/+/, \"\")\n .replace(/^controllers\\//, \"\")\n .replace(\"_controller\", \"\")\n .replace(/\\//g, \"--\")\n .replace(/_/g, \"-\")\n .replace(/\\.js$/, \"\")\n }\n\n #registerController(name, module) {\n this.application.unload(name)\n this.application.register(name, module.default)\n }\n\n #deregisterController(name) {\n log(`\\tRemoving controller ${name}`)\n this.application.unload(name)\n }\n}\n","import { Idiomorph } from \"idiomorph/dist/idiomorph.esm.js\"\nimport { reloadHtmlDocument } from \"../helpers.js\"\nimport { log } from \"../logger.js\"\nimport { StimulusReloader } from \"./stimulus_reloader.js\"\n\nexport class MorphHtmlReloader {\n static async reload() {\n return new MorphHtmlReloader().reload()\n }\n\n async reload() {\n await this.#reloadHtml()\n await this.#reloadStimulus()\n }\n\n async #reloadHtml() {\n log(\"Reload html with morph...\")\n\n const reloadedDocument = await reloadHtmlDocument()\n this.#updateBody(reloadedDocument.body)\n return reloadedDocument\n }\n\n #updateBody(newBody) {\n Idiomorph.morph(document.body, newBody)\n }\n\n async #reloadStimulus() {\n await StimulusReloader.reloadAll()\n }\n}\n","import { log } from \"../logger.js\"\nimport { cacheBustedUrl, reloadHtmlDocument, pathWithoutAssetDigest } from \"../helpers.js\"\n\nexport class CssReloader {\n static async reload(...params) {\n return new CssReloader(...params).reload()\n }\n\n constructor(filePattern = /./) {\n this.filePattern = filePattern\n }\n\n async reload() {\n log(\"Reload css...\")\n await Promise.all(await this.#reloadAllLinks())\n }\n\n async #reloadAllLinks() {\n const cssLinks = await this.#loadNewCssLinks();\n return cssLinks.map(link => this.#reloadLinkIfNeeded(link))\n }\n\n async #loadNewCssLinks() {\n const reloadedDocument = await reloadHtmlDocument()\n return Array.from(reloadedDocument.head.querySelectorAll(\"link[rel='stylesheet']\"))\n }\n\n #reloadLinkIfNeeded(link) {\n if (this.#shouldReloadLink(link)) {\n return this.#reloadLink(link)\n } else {\n return Promise.resolve()\n }\n }\n\n #shouldReloadLink(link) {\n return this.filePattern.test(link.getAttribute(\"href\"))\n }\n\n async #reloadLink(link) {\n return new Promise(resolve => {\n const href = link.getAttribute(\"href\")\n const newLink = this.#findExistingLinkFor(link) || this.#appendNewLink(link)\n\n newLink.setAttribute(\"href\", cacheBustedUrl(link.getAttribute(\"href\")))\n newLink.onload = () => {\n log(`\\t${href}`)\n resolve()\n }\n })\n }\n\n #findExistingLinkFor(link) {\n return this.#cssLinks.find(newLink => pathWithoutAssetDigest(link.href) === pathWithoutAssetDigest(newLink.href))\n }\n\n get #cssLinks() {\n return Array.from(document.querySelectorAll(\"link[rel='stylesheet']\"))\n }\n\n #appendNewLink(link) {\n document.head.append(link)\n return link\n }\n}\n","import { log } from \"../logger.js\"\n\nexport class ReplaceHtmlReloader {\n static async reload() {\n return new ReplaceHtmlReloader().reload()\n }\n\n async reload() {\n await this.#reloadHtml()\n }\n\n async #reloadHtml() {\n log(\"Reload html with Turbo...\")\n\n this.#keepScrollPosition()\n await this.#visitCurrentPage()\n }\n\n #keepScrollPosition() {\n document.addEventListener(\"turbo:before-render\", () => {\n Turbo.navigator.currentVisit.scrolled = true\n }, { once: true })\n }\n\n #visitCurrentPage() {\n return new Promise(resolve => {\n document.addEventListener(\"turbo:load\", () => resolve(document), { once: true })\n window.Turbo.visit(window.location)\n })\n }\n}\n","import consumer from \"./consumer\"\nimport { assetNameFromPath } from \"../helpers.js\";\nimport { MorphHtmlReloader } from \"../reloaders/morph_html_reloader.js\";\nimport { CssReloader } from \"../reloaders/css_reloader.js\";\nimport { StimulusReloader } from \"../reloaders/stimulus_reloader.js\";\nimport { ReplaceHtmlReloader } from \"../reloaders/replace_html_reloader.js\";\n\nconsumer.subscriptions.create({ channel: \"Hotwire::Spark::Channel\" }, {\n connected() {\n document.body.setAttribute(\"data-hotwire-spark-ready\", \"\")\n },\n\n async received(message) {\n try {\n await this.dispatch(message)\n } catch(error) {\n console.log(`Error on ${message.action}`, error)\n }\n },\n\n dispatch({ action, path }) {\n switch(action) {\n case \"reload_html\":\n return this.reloadHtml()\n case \"reload_css\":\n return this.reloadCss(path)\n case \"reload_stimulus\":\n return this.reloadStimulus(path)\n default:\n throw new Error(`Unknown action: ${action}`)\n }\n },\n\n reloadHtml() {\n const htmlReloader = HotwireSpark.config.htmlReloadMethod == \"morph\" ? MorphHtmlReloader : ReplaceHtmlReloader\n return htmlReloader.reload()\n },\n\n reloadCss(path) {\n const fileName = assetNameFromPath(path)\n return CssReloader.reload(new RegExp(fileName))\n },\n\n reloadStimulus(path) {\n return StimulusReloader.reload(path)\n }\n})\n\n","import \"./channels/monitoring_channel.js\"\nimport { getConfigurationProperty } from \"./helpers.js\";\n\nconst HotwireSpark = {\n config: {\n loggingEnabled: false,\n htmlReloadMethod: \"morph\"\n }\n}\n\nconst configProperties = {\n loggingEnabled: \"logging\",\n htmlReloadMethod: \"html-reload-method\",\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n Object.entries(configProperties).forEach(([key, property]) => {\n HotwireSpark.config[key] = getConfigurationProperty(property)\n })\n})\n\nexport default HotwireSpark\n"],"names":["adapters","logger","console","undefined","WebSocket","log","messages","this","enabled","push","Date","now","getTime","secondsSince","time","ConnectionMonitor","constructor","connection","visibilityDidChange","bind","reconnectAttempts","start","isRunning","startedAt","stoppedAt","startPolling","addEventListener","staleThreshold","stop","stopPolling","removeEventListener","recordMessage","pingedAt","recordConnect","disconnectedAt","recordDisconnect","poll","clearTimeout","pollTimeout","setTimeout","reconnectIfStale","getPollInterval","reconnectionBackoffRate","Math","pow","min","random","connectionIsStale","refreshedAt","disconnectedRecently","reopen","document","visibilityState","isOpen","INTERNAL","message_types","welcome","disconnect","ping","confirmation","rejection","disconnect_reasons","unauthorized","invalid_request","server_restart","remote","default_mount_path","protocols","supportedProtocols","slice","length","indexOf","Connection","consumer","open","subscriptions","monitor","disconnected","send","data","webSocket","JSON","stringify","isActive","getState","socketProtocols","subprotocols","uninstallEventHandlers","url","installEventHandlers","close","allowReconnect","error","reopenDelay","getProtocol","protocol","isState","triedToReconnect","isProtocolSupported","call","states","state","readyState","toLowerCase","eventName","events","handler","prototype","message","event","identifier","reason","reconnect","type","parse","reconnectAttempted","reload","confirmSubscription","notify","reconnected","reject","notifyAll","willAttemptReconnect","Subscription","params","mixin","object","properties","key","value","extend","perform","action","command","unsubscribe","remove","SubscriptionGuarantor","pendingSubscriptions","guarantee","subscription","startGuaranteeing","forget","filter","s","stopGuaranteeing","retrySubscribing","retryTimeout","subscribe","map","Subscriptions","guarantor","create","channelName","channel","add","ensureActiveConnection","findAll","sendCommand","callbackName","args","Consumer","_url","test","a","createElement","href","replace","createWebSocketURL","connect","addSubProtocol","subprotocol","createConsumer","name","element","head","querySelector","getAttribute","getConfig","pathWithoutAssetDigest","path","urlWithParams","urlString","URL","window","location","origin","Object","entries","forEach","_ref","searchParams","set","toString","cacheBustedUrl","async","reloadHtmlDocument","currentUrl","hotwire_spark","response","fetch","headers","Accept","ok","Error","status","fetchedHTML","text","DOMParser","parseFromString","Idiomorph","EMPTY_SET","Set","defaults","morphStyle","callbacks","beforeNodeAdded","noOp","afterNodeAdded","beforeNodeMorphed","afterNodeMorphed","beforeNodeRemoved","afterNodeRemoved","beforeAttributeUpdated","style","shouldPreserve","elt","shouldReAppend","shouldRemove","afterHeadMorphed","morphNormalizedContent","oldNode","normalizedNewContent","ctx","block","oldHead","newHead","promises","handleHeadElement","Promise","all","then","assign","ignore","morphChildren","children","bestMatch","newContent","currentElement","firstChild","bestElement","score","newScore","scoreElement","nextSibling","findBestNodeMatch","previousSibling","morphedNode","morphOldNodeTo","stack","added","node","pop","parentElement","insertBefore","insertSiblings","ignoreValueOfActiveElement","possibleActiveElement","ignoreActiveValue","activeElement","ignoreActive","isSoftMatch","HTMLHeadElement","from","to","nodeType","fromAttributes","attributes","toAttributes","fromAttribute","ignoreAttribute","setAttribute","i","toAttribute","hasAttribute","removeAttribute","nodeValue","HTMLInputElement","fromValue","toValue","syncBooleanAttribute","HTMLOptionElement","HTMLTextAreaElement","syncInputValue","syncNodeFrom","replaceChild","newParent","oldParent","newChild","nextNewChild","insertionPoint","appendChild","removeIdsFromConsideration","isIdSetMatch","idSetMatch","findIdSetMatch","removeNodesBetween","softMatch","findSoftMatch","tempNode","removeNode","attr","updateType","attributeName","ignoreUpdate","newHeadTag","currentHead","removed","preserved","nodesToAppend","headMergeStyle","srcToNewHeadNodes","Map","newHeadChild","outerHTML","currentHeadElt","inNewContent","has","isReAppended","isPreserved","delete","values","newNode","newElt","createRange","createContextualFragment","src","resolve","promise","_resolve","removedElement","removeChild","kept","node1","node2","tagName","id","getIdIntersectionCount","startInclusive","endExclusive","newChildPotentialIdCount","potentialMatch","otherMatchCount","potentialSoftMatch","siblingSoftMatchCount","isIdInConsideration","deadIds","idIsWithinNode","targetNode","idMap","get","idSet","sourceSet","matchCount","populateIdMapForNode","nodeParent","idElements","querySelectorAll","current","createIdMap","oldContent","morph","config","Document","documentElement","parser","contentWithSvgsRemoved","match","content","generatedByIdiomorph","htmlElement","body","parseContent","normalizedContent","Node","dummyParent","append","normalizeContent","finalConfig","mergeDefaults","target","createMorphContext","HotwireSpark","loggingEnabled","_len","arguments","Array","_key","StimulusReloader","changedFilePath","reloadAll","Stimulus","controllers","controller","unload","register","application","reloadChangedStimulusControllers","unloadDeletedStimulusControllers","stimulusControllerPathsToReload","reloadStimulusController","moduleName","controllerPathsToReload","stimulusControllerPaths","shouldReloadController","keys","stimulusPathsByModule","endsWith","extractControllerName","changedControllerIdentifier","pathsByModule","parseImportmapJson","importmapScript","imports","controllerName","pathForModuleName","module","import","registerController","controllersToUnload","deregisterController","didChangeTriggerAReload","default","MorphHtmlReloader","reloadHtml","reloadStimulus","reloadedDocument","updateBody","newBody","CssReloader","filePattern","reloadAllLinks","loadNewCssLinks","link","reloadLinkIfNeeded","shouldReloadLink","reloadLink","newLink","findExistingLinkFor","appendNewLink","onload","cssLinks","find","ReplaceHtmlReloader","keepScrollPosition","visitCurrentPage","Turbo","navigator","currentVisit","scrolled","once","visit","connected","received","dispatch","reloadCss","htmlReloadMethod","fileName","split","assetNameFromPath","RegExp","configProperties","property"],"mappings":"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","x_google_ignoreList":[0,3]}
|
@@ -12,11 +12,11 @@ export class ReplaceHtmlReloader {
|
|
12
12
|
async #reloadHtml() {
|
13
13
|
log("Reload html with Turbo...")
|
14
14
|
|
15
|
-
this.#
|
15
|
+
this.#keepScrollPosition()
|
16
16
|
await this.#visitCurrentPage()
|
17
17
|
}
|
18
18
|
|
19
|
-
#
|
19
|
+
#keepScrollPosition() {
|
20
20
|
document.addEventListener("turbo:before-render", () => {
|
21
21
|
Turbo.navigator.currentVisit.scrolled = true
|
22
22
|
}, { once: true })
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import { log } from "../logger.js"
|
2
|
+
import { cacheBustedUrl, reloadHtmlDocument } from "../helpers.js"
|
2
3
|
|
3
4
|
export class StimulusReloader {
|
4
|
-
static async reload(
|
5
|
-
|
5
|
+
static async reload(changedFilePath) {
|
6
|
+
const document = await reloadHtmlDocument()
|
7
|
+
return new StimulusReloader(document, changedFilePath).reload()
|
6
8
|
}
|
7
9
|
|
8
10
|
static async reloadAll() {
|
@@ -14,8 +16,9 @@ export class StimulusReloader {
|
|
14
16
|
return Promise.resolve()
|
15
17
|
}
|
16
18
|
|
17
|
-
constructor(
|
18
|
-
this.
|
19
|
+
constructor(document, changedFilePath) {
|
20
|
+
this.document = document
|
21
|
+
this.changedFilePath = changedFilePath
|
19
22
|
this.application = window.Stimulus
|
20
23
|
}
|
21
24
|
|
@@ -24,63 +27,88 @@ export class StimulusReloader {
|
|
24
27
|
|
25
28
|
this.application.stop()
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
}
|
30
|
-
catch(error) {
|
31
|
-
if (error instanceof SourceFileNotFound) {
|
32
|
-
this.#deregisterChangedController()
|
33
|
-
} else {
|
34
|
-
console.error("Error reloading controller", error)
|
35
|
-
}
|
36
|
-
}
|
30
|
+
await this.#reloadChangedStimulusControllers()
|
31
|
+
this.#unloadDeletedStimulusControllers()
|
37
32
|
|
38
33
|
this.application.start()
|
39
34
|
}
|
40
35
|
|
41
|
-
async #
|
42
|
-
|
43
|
-
|
36
|
+
async #reloadChangedStimulusControllers() {
|
37
|
+
await Promise.all(
|
38
|
+
this.#stimulusControllerPathsToReload.map(async moduleName => this.#reloadStimulusController(moduleName))
|
39
|
+
)
|
44
40
|
}
|
45
41
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
throw new SourceFileNotFound(`Source file not found: ${path}`)
|
51
|
-
}
|
52
|
-
|
53
|
-
const sourceCode = await response.text()
|
42
|
+
get #stimulusControllerPathsToReload() {
|
43
|
+
this.controllerPathsToReload = this.controllerPathsToReload || this.#stimulusControllerPaths.filter(path => this.#shouldReloadController(path))
|
44
|
+
return this.controllerPathsToReload
|
45
|
+
}
|
54
46
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
URL.revokeObjectURL(moduleUrl)
|
47
|
+
get #stimulusControllerPaths() {
|
48
|
+
return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith("_controller"))
|
49
|
+
}
|
59
50
|
|
60
|
-
|
51
|
+
#shouldReloadController(path) {
|
52
|
+
return this.#extractControllerName(path) === this.#changedControllerIdentifier
|
61
53
|
}
|
62
54
|
|
63
55
|
get #changedControllerIdentifier() {
|
64
|
-
this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.
|
56
|
+
this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.changedFilePath)
|
65
57
|
return this.changedControllerIdentifier
|
66
58
|
}
|
67
59
|
|
60
|
+
get #stimulusPathsByModule() {
|
61
|
+
this.pathsByModule = this.pathsByModule || this.#parseImportmapJson()
|
62
|
+
return this.pathsByModule
|
63
|
+
}
|
64
|
+
|
65
|
+
#parseImportmapJson() {
|
66
|
+
const importmapScript = this.document.querySelector("script[type=importmap]")
|
67
|
+
return JSON.parse(importmapScript.text).imports
|
68
|
+
}
|
69
|
+
|
70
|
+
async #reloadStimulusController(moduleName) {
|
71
|
+
log(`\t${moduleName}`)
|
72
|
+
|
73
|
+
const controllerName = this.#extractControllerName(moduleName)
|
74
|
+
const path = cacheBustedUrl(this.#pathForModuleName(moduleName))
|
75
|
+
|
76
|
+
const module = await import(path)
|
77
|
+
|
78
|
+
this.#registerController(controllerName, module)
|
79
|
+
}
|
80
|
+
|
81
|
+
#unloadDeletedStimulusControllers() {
|
82
|
+
this.#controllersToUnload.forEach(controller => this.#deregisterController(controller.identifier))
|
83
|
+
}
|
84
|
+
|
85
|
+
get #controllersToUnload() {
|
86
|
+
if (this.#didChangeTriggerAReload) {
|
87
|
+
return []
|
88
|
+
} else {
|
89
|
+
return this.application.controllers.filter(controller => this.#changedControllerIdentifier === controller.identifier)
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
get #didChangeTriggerAReload() {
|
94
|
+
return this.#stimulusControllerPathsToReload.length > 0
|
95
|
+
}
|
96
|
+
|
97
|
+
#pathForModuleName(moduleName) {
|
98
|
+
return this.#stimulusPathsByModule[moduleName]
|
99
|
+
}
|
100
|
+
|
68
101
|
#extractControllerName(path) {
|
69
102
|
return path
|
70
|
-
.replace(
|
103
|
+
.replace(/^\/+/, "")
|
104
|
+
.replace(/^controllers\//, "")
|
71
105
|
.replace("_controller", "")
|
72
106
|
.replace(/\//g, "--")
|
73
107
|
.replace(/_/g, "-")
|
74
108
|
.replace(/\.js$/, "")
|
75
109
|
}
|
76
110
|
|
77
|
-
#deregisterChangedController() {
|
78
|
-
this.#deregisterController(this.#changedControllerIdentifier)
|
79
|
-
}
|
80
|
-
|
81
111
|
#registerController(name, module) {
|
82
|
-
log("\tReloading controller", name)
|
83
|
-
|
84
112
|
this.application.unload(name)
|
85
113
|
this.application.register(name, module.default)
|
86
114
|
}
|
@@ -90,5 +118,3 @@ export class StimulusReloader {
|
|
90
118
|
this.application.unload(name)
|
91
119
|
}
|
92
120
|
}
|
93
|
-
|
94
|
-
class SourceFileNotFound extends Error { }
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Hotwire::Spark::Change
|
2
|
+
attr_reader :paths, :extensions, :changed_path, :action
|
3
|
+
|
4
|
+
def initialize(paths, extensions, changed_path, action)
|
5
|
+
@paths = paths
|
6
|
+
@extensions = extensions
|
7
|
+
@changed_path = changed_path
|
8
|
+
@action = action
|
9
|
+
end
|
10
|
+
|
11
|
+
def broadcast
|
12
|
+
broadcast_reload_action if should_broadcast?
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def broadcast_reload_action
|
17
|
+
Hotwire::Spark.cable_server.broadcast "hotwire_spark", reload_message
|
18
|
+
end
|
19
|
+
|
20
|
+
def reload_message
|
21
|
+
{ action: action, path: canonical_changed_path }
|
22
|
+
end
|
23
|
+
|
24
|
+
def canonical_changed_path
|
25
|
+
canonical_changed_path = changed_path
|
26
|
+
paths.each { |path| canonical_changed_path = canonical_changed_path.to_s.gsub(/^#{path}/, "") }
|
27
|
+
canonical_changed_path
|
28
|
+
end
|
29
|
+
|
30
|
+
def should_broadcast?
|
31
|
+
changed_path.to_s =~ extension_regexp
|
32
|
+
end
|
33
|
+
|
34
|
+
def extension_regexp
|
35
|
+
/#{extensions.map { |ext| "\\." + ext }.join("|")}$/
|
36
|
+
end
|
37
|
+
end
|
@@ -5,7 +5,6 @@ class Hotwire::Spark::Installer
|
|
5
5
|
|
6
6
|
def install
|
7
7
|
configure_cable_server
|
8
|
-
configure_routes
|
9
8
|
configure_middleware
|
10
9
|
monitor_paths
|
11
10
|
end
|
@@ -20,12 +19,6 @@ class Hotwire::Spark::Installer
|
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
def configure_routes
|
24
|
-
application.routes.prepend do
|
25
|
-
mount Hotwire::Spark::Engine => "/spark", as: "hotwire_spark"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
22
|
def configure_middleware
|
30
23
|
middleware.use Hotwire::Spark::Middleware
|
31
24
|
end
|
@@ -45,20 +38,11 @@ class Hotwire::Spark::Installer
|
|
45
38
|
paths = Hotwire::Spark.public_send(paths_name)
|
46
39
|
if paths.present?
|
47
40
|
file_watcher.monitor paths do |file_path|
|
48
|
-
|
49
|
-
broadcast_reload_action(action, file_path) if file_path.to_s =~ pattern
|
41
|
+
Hotwire::Spark::Change.new(paths, extensions, file_path, action).broadcast
|
50
42
|
end
|
51
43
|
end
|
52
44
|
end
|
53
45
|
|
54
|
-
def broadcast_reload_action(action, file_path)
|
55
|
-
Hotwire::Spark.cable_server.broadcast "hotwire_spark", reload_message_for(action, file_path)
|
56
|
-
end
|
57
|
-
|
58
|
-
def reload_message_for(action, file_path)
|
59
|
-
{ action: action, path: file_path }
|
60
|
-
end
|
61
|
-
|
62
46
|
def file_watcher
|
63
47
|
@file_watches ||= Hotwire::Spark::FileWatcher.new
|
64
48
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotwire-spark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jorge Manrubia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -125,7 +125,6 @@ files:
|
|
125
125
|
- app/assets/javascripts/hotwire_spark.min.js.map
|
126
126
|
- app/assets/stylesheets/hotwire_spark/application.css
|
127
127
|
- app/channels/hotwire/spark/channel.rb
|
128
|
-
- app/controllers/hotwire/spark/source_files_controller.rb
|
129
128
|
- app/javascript/hotwire/spark/channels/consumer.js
|
130
129
|
- app/javascript/hotwire/spark/channels/monitoring_channel.js
|
131
130
|
- app/javascript/hotwire/spark/helpers.js
|
@@ -138,6 +137,7 @@ files:
|
|
138
137
|
- config/routes.rb
|
139
138
|
- lib/hotwire-spark.rb
|
140
139
|
- lib/hotwire/spark/action_cable/server.rb
|
140
|
+
- lib/hotwire/spark/change.rb
|
141
141
|
- lib/hotwire/spark/default_options.rb
|
142
142
|
- lib/hotwire/spark/engine.rb
|
143
143
|
- lib/hotwire/spark/file_watcher.rb
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class Hotwire::Spark::SourceFilesController < ActionController::Base
|
2
|
-
def show
|
3
|
-
if File.exist?(path_param)
|
4
|
-
render plain: File.read(path_param)
|
5
|
-
else
|
6
|
-
head :not_found
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
11
|
-
def path_param
|
12
|
-
Rails.root.join params[:path]
|
13
|
-
end
|
14
|
-
end
|