htmx.org 4.0.0-alpha3 → 4.0.0-alpha4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,588 @@
1
+ (() => {
2
+ let api;
3
+
4
+ // Helper to get attribute value, checking colon, hyphen, and plain variants
5
+ function getWsAttribute(element, attrName) {
6
+ // Try colon variant first (hx-ws:connect)
7
+ let colonValue = api.attributeValue(element, 'hx-ws:' + attrName);
8
+ if (colonValue !== null && colonValue !== undefined) return colonValue;
9
+
10
+ // Try hyphen variant for JSX (hx-ws-connect)
11
+ let hyphenValue = api.attributeValue(element, 'hx-ws-' + attrName);
12
+ if (hyphenValue !== null && hyphenValue !== undefined) return hyphenValue;
13
+
14
+ // For 'send', also check plain 'hx-ws' (marker attribute)
15
+ if (attrName === 'send') {
16
+ let plainValue = api.attributeValue(element, 'hx-ws');
17
+ if (plainValue !== null && plainValue !== undefined) return plainValue;
18
+ }
19
+
20
+ return null;
21
+ }
22
+
23
+ // Helper to check if element has WebSocket attribute (any variant)
24
+ function hasWsAttribute(element, attrName) {
25
+ let value = getWsAttribute(element, attrName);
26
+ return value !== null && value !== undefined;
27
+ }
28
+
29
+ // ========================================
30
+ // CONFIGURATION
31
+ // ========================================
32
+
33
+ function getConfig() {
34
+ const defaults = {
35
+ reconnect: true,
36
+ reconnectDelay: 1000,
37
+ reconnectMaxDelay: 30000,
38
+ reconnectJitter: true,
39
+ autoConnect: false,
40
+ pauseInBackground: true
41
+ };
42
+ return { ...defaults, ...(htmx.config.websockets || {}) };
43
+ }
44
+
45
+ // ========================================
46
+ // CONNECTION REGISTRY
47
+ // ========================================
48
+
49
+ const connectionRegistry = new Map();
50
+
51
+ function getOrCreateConnection(url, element) {
52
+ if (connectionRegistry.has(url)) {
53
+ let entry = connectionRegistry.get(url);
54
+ entry.refCount++;
55
+ entry.elements.add(element);
56
+ return entry;
57
+ }
58
+
59
+ let entry = {
60
+ socket: null,
61
+ refCount: 1,
62
+ elements: new Set([element]),
63
+ reconnectAttempts: 0,
64
+ reconnectTimer: null,
65
+ pendingRequests: new Map()
66
+ };
67
+
68
+ connectionRegistry.set(url, entry);
69
+ createWebSocket(url, entry);
70
+ return entry;
71
+ }
72
+
73
+ function createWebSocket(url, entry) {
74
+ let firstElement = entry.elements.values().next().value;
75
+ if (firstElement) {
76
+ if (!triggerEvent(firstElement, 'htmx:before:ws:connect', { url })) {
77
+ return;
78
+ }
79
+ }
80
+
81
+ try {
82
+ entry.socket = new WebSocket(url);
83
+
84
+ entry.socket.addEventListener('open', () => {
85
+ // Don't reset reconnectAttempts immediately - allow backoff to persist across quick reconnections
86
+ // It will naturally decrease as the connection remains stable
87
+ if (firstElement) {
88
+ triggerEvent(firstElement, 'htmx:after:ws:connect', { url, socket: entry.socket });
89
+ }
90
+ });
91
+
92
+ entry.socket.addEventListener('message', (event) => {
93
+ handleMessage(entry, event);
94
+ });
95
+
96
+ entry.socket.addEventListener('close', () => {
97
+ if (firstElement) {
98
+ triggerEvent(firstElement, 'htmx:ws:close', { url });
99
+ }
100
+
101
+ // Check if entry is still valid (not cleared)
102
+ if (!connectionRegistry.has(url)) return;
103
+
104
+ let config = getConfig();
105
+ if (config.reconnect && entry.refCount > 0) {
106
+ scheduleReconnect(url, entry);
107
+ } else {
108
+ connectionRegistry.delete(url);
109
+ }
110
+ });
111
+
112
+ entry.socket.addEventListener('error', (error) => {
113
+ if (firstElement) {
114
+ triggerEvent(firstElement, 'htmx:ws:error', { url, error });
115
+ }
116
+ });
117
+ } catch (error) {
118
+ if (firstElement) {
119
+ triggerEvent(firstElement, 'htmx:ws:error', { url, error });
120
+ }
121
+ }
122
+ }
123
+
124
+ function scheduleReconnect(url, entry) {
125
+ let config = getConfig();
126
+
127
+ // Increment attempts before calculating delay for proper exponential backoff
128
+ let attempts = entry.reconnectAttempts;
129
+ entry.reconnectAttempts++;
130
+
131
+ let delay = Math.min(
132
+ (config.reconnectDelay || 1000) * Math.pow(2, attempts),
133
+ config.reconnectMaxDelay || 30000
134
+ );
135
+
136
+ if (config.reconnectJitter) {
137
+ delay = delay * (0.75 + Math.random() * 0.5);
138
+ }
139
+
140
+ entry.reconnectTimer = setTimeout(() => {
141
+ if (entry.refCount > 0) {
142
+ let firstElement = entry.elements.values().next().value;
143
+ if (firstElement) {
144
+ triggerEvent(firstElement, 'htmx:ws:reconnect', { url, attempts });
145
+ }
146
+ createWebSocket(url, entry);
147
+ }
148
+ }, delay);
149
+ }
150
+
151
+ function decrementRef(url, element) {
152
+ if (!connectionRegistry.has(url)) return;
153
+
154
+ let entry = connectionRegistry.get(url);
155
+ entry.elements.delete(element);
156
+ entry.refCount--;
157
+
158
+ if (entry.refCount <= 0) {
159
+ if (entry.reconnectTimer) {
160
+ clearTimeout(entry.reconnectTimer);
161
+ }
162
+ if (entry.socket && entry.socket.readyState === WebSocket.OPEN) {
163
+ entry.socket.close();
164
+ }
165
+ connectionRegistry.delete(url);
166
+ }
167
+ }
168
+
169
+ // ========================================
170
+ // MESSAGE SENDING
171
+ // ========================================
172
+
173
+ function sendMessage(element, event) {
174
+ // Find connection URL
175
+ let url = getWsAttribute(element, 'send');
176
+ if (!url) {
177
+ // Look for nearest ancestor with hx-ws:connect or hx-ws-connect
178
+ let prefix = htmx.config.prefix || '';
179
+ let ancestor = element.closest('[' + prefix + 'hx-ws\\:connect],[' + prefix + 'hx-ws-connect]');
180
+ if (ancestor) {
181
+ url = getWsAttribute(ancestor, 'connect');
182
+ }
183
+ }
184
+
185
+ if (!url) {
186
+ console.error('No WebSocket connection found for hx-ws:send element', element);
187
+ return;
188
+ }
189
+
190
+ let entry = connectionRegistry.get(url);
191
+ if (!entry || !entry.socket || entry.socket.readyState !== WebSocket.OPEN) {
192
+ triggerEvent(element, 'htmx:wsSendError', { url, error: 'Connection not open' });
193
+ return;
194
+ }
195
+
196
+ // Build message
197
+ let form = element.form || element.closest('form');
198
+ let body = api.collectFormData(element, form, event.submitter);
199
+ api.handleHxVals(element, body);
200
+
201
+ let values = {};
202
+ for (let [key, value] of body) {
203
+ values[key] = value;
204
+ }
205
+
206
+ let requestId = generateUUID();
207
+ let message = {
208
+ type: 'request',
209
+ request_id: requestId,
210
+ event: event.type,
211
+ values: values,
212
+ path: url
213
+ };
214
+
215
+ if (element.id) {
216
+ message.id = element.id;
217
+ }
218
+
219
+ // Allow modification via event
220
+ let detail = { message, element, url };
221
+ if (!triggerEvent(element, 'htmx:before:ws:send', detail)) {
222
+ return;
223
+ }
224
+
225
+ try {
226
+ entry.socket.send(JSON.stringify(detail.message));
227
+
228
+ // Store pending request for response matching
229
+ entry.pendingRequests.set(requestId, { element, timestamp: Date.now() });
230
+
231
+ triggerEvent(element, 'htmx:after:ws:send', { message: detail.message, url });
232
+ } catch (error) {
233
+ triggerEvent(element, 'htmx:wsSendError', { url, error });
234
+ }
235
+ }
236
+
237
+ function generateUUID() {
238
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
239
+ let r = Math.random() * 16 | 0;
240
+ let v = c === 'x' ? r : (r & 0x3 | 0x8);
241
+ return v.toString(16);
242
+ });
243
+ }
244
+
245
+ // ========================================
246
+ // MESSAGE RECEIVING & ROUTING
247
+ // ========================================
248
+
249
+ function handleMessage(entry, event) {
250
+ let envelope;
251
+ try {
252
+ envelope = JSON.parse(event.data);
253
+ } catch (e) {
254
+ // Not JSON, emit unknown message event
255
+ let firstElement = entry.elements.values().next().value;
256
+ if (firstElement) {
257
+ triggerEvent(firstElement, 'htmx:wsUnknownMessage', { data: event.data });
258
+ }
259
+ return;
260
+ }
261
+
262
+ // Apply defaults for channel and format
263
+ envelope.channel = envelope.channel || 'ui';
264
+ envelope.format = envelope.format || 'html';
265
+
266
+ // Find target element for this message
267
+ let targetElement = null;
268
+ if (envelope.request_id && entry.pendingRequests.has(envelope.request_id)) {
269
+ targetElement = entry.pendingRequests.get(envelope.request_id).element;
270
+ entry.pendingRequests.delete(envelope.request_id);
271
+ } else {
272
+ // Use first element in the connection
273
+ targetElement = entry.elements.values().next().value;
274
+ }
275
+
276
+ // Emit before:message event (cancelable)
277
+ if (!triggerEvent(targetElement, 'htmx:before:ws:message', { envelope, element: targetElement })) {
278
+ return;
279
+ }
280
+
281
+ // Route based on channel
282
+ if (envelope.channel === 'ui' && envelope.format === 'html') {
283
+ handleHtmlMessage(targetElement, envelope);
284
+ } else if (envelope.channel && (envelope.channel === 'audio' || envelope.channel === 'json' || envelope.channel === 'binary')) {
285
+ // Known custom channel - emit event for extensions to handle
286
+ triggerEvent(targetElement, 'htmx:wsMessage', { ...envelope, element: targetElement });
287
+ } else {
288
+ // Unknown channel/format - emit unknown message event
289
+ triggerEvent(targetElement, 'htmx:wsUnknownMessage', { ...envelope, element: targetElement });
290
+ }
291
+
292
+ triggerEvent(targetElement, 'htmx:after:ws:message', { envelope, element: targetElement });
293
+ }
294
+
295
+ // ========================================
296
+ // HTML PARTIAL HANDLING
297
+ // ========================================
298
+
299
+ function handleHtmlMessage(element, envelope) {
300
+ let parser = new DOMParser();
301
+ let doc = parser.parseFromString(envelope.payload, 'text/html');
302
+
303
+ // Find all hx-partial elements
304
+ let partials = doc.querySelectorAll('hx-partial');
305
+
306
+ if (partials.length === 0) {
307
+ // No partials, treat entire payload as content for element's target
308
+ let target = resolveTarget(element);
309
+ if (target) {
310
+ swapContent(target, envelope.payload, element);
311
+ }
312
+ return;
313
+ }
314
+
315
+ partials.forEach(partial => {
316
+ let targetId = partial.getAttribute('id');
317
+ if (!targetId) return;
318
+
319
+ let target = document.getElementById(targetId);
320
+ if (!target) return;
321
+
322
+ swapContent(target, partial.innerHTML, element);
323
+ });
324
+ }
325
+
326
+ function resolveTarget(element) {
327
+ let targetSelector = api.attributeValue(element, 'hx-target');
328
+ if (targetSelector) {
329
+ if (targetSelector === 'this') {
330
+ return element;
331
+ }
332
+ return document.querySelector(targetSelector);
333
+ }
334
+ return element;
335
+ }
336
+
337
+ function swapContent(target, content, sourceElement) {
338
+ let swapStyle = api.attributeValue(sourceElement, 'hx-swap') || htmx.config.defaultSwap;
339
+
340
+ // Parse swap style (just get the main style, ignore modifiers for now)
341
+ let style = swapStyle.split(' ')[0];
342
+
343
+ // Normalize swap style
344
+ style = normalizeSwapStyle(style);
345
+
346
+ // Perform swap
347
+ switch (style) {
348
+ case 'innerHTML':
349
+ target.innerHTML = content;
350
+ break;
351
+ case 'outerHTML':
352
+ target.outerHTML = content;
353
+ break;
354
+ case 'beforebegin':
355
+ target.insertAdjacentHTML('beforebegin', content);
356
+ break;
357
+ case 'afterbegin':
358
+ target.insertAdjacentHTML('afterbegin', content);
359
+ break;
360
+ case 'beforeend':
361
+ target.insertAdjacentHTML('beforeend', content);
362
+ break;
363
+ case 'afterend':
364
+ target.insertAdjacentHTML('afterend', content);
365
+ break;
366
+ case 'delete':
367
+ target.remove();
368
+ break;
369
+ case 'none':
370
+ // Do nothing
371
+ break;
372
+ default:
373
+ target.innerHTML = content;
374
+ }
375
+
376
+ // Process new content with HTMX
377
+ htmx.process(target);
378
+ }
379
+
380
+ function normalizeSwapStyle(style) {
381
+ return style === 'before' ? 'beforebegin' :
382
+ style === 'after' ? 'afterend' :
383
+ style === 'prepend' ? 'afterbegin' :
384
+ style === 'append' ? 'beforeend' : style;
385
+ }
386
+
387
+ // ========================================
388
+ // EVENT HELPERS
389
+ // ========================================
390
+
391
+ function triggerEvent(element, eventName, detail = {}) {
392
+ if (!element) return true;
393
+ return htmx.trigger(element, eventName, detail);
394
+ }
395
+
396
+ // ========================================
397
+ // ELEMENT LIFECYCLE
398
+ // ========================================
399
+
400
+ function initializeElement(element) {
401
+ if (element._htmx?.wsInitialized) return;
402
+
403
+ let connectUrl = getWsAttribute(element, 'connect');
404
+ if (!connectUrl) return;
405
+
406
+ element._htmx = element._htmx || {};
407
+ element._htmx.wsInitialized = true;
408
+
409
+ let config = getConfig();
410
+ let triggerSpec = api.attributeValue(element, 'hx-trigger');
411
+
412
+ if (!triggerSpec && config.autoConnect === true) {
413
+ // Auto-connect on element initialization
414
+ getOrCreateConnection(connectUrl, element);
415
+ element._htmx = element._htmx || {};
416
+ element._htmx.wsUrl = connectUrl;
417
+ } else if (triggerSpec) {
418
+ // Connect based on trigger
419
+ let specs = api.parseTriggerSpecs(triggerSpec);
420
+ if (specs.length > 0) {
421
+ let spec = specs[0];
422
+ if (spec.name === 'load') {
423
+ getOrCreateConnection(connectUrl, element);
424
+ element._htmx = element._htmx || {};
425
+ element._htmx.wsUrl = connectUrl;
426
+ } else {
427
+ // Set up event listener for other triggers
428
+ element.addEventListener(spec.name, () => {
429
+ if (!element._htmx?.wsUrl) {
430
+ getOrCreateConnection(connectUrl, element);
431
+ element._htmx = element._htmx || {};
432
+ element._htmx.wsUrl = connectUrl;
433
+ }
434
+ }, { once: true });
435
+ }
436
+ }
437
+ }
438
+ }
439
+
440
+ function initializeSendElement(element) {
441
+ if (element._htmx?.wsSendInitialized) return;
442
+
443
+ let sendUrl = getWsAttribute(element, 'send');
444
+ let triggerSpec = api.attributeValue(element, 'hx-trigger');
445
+
446
+ if (!triggerSpec) {
447
+ // Default trigger based on element type
448
+ triggerSpec = element.matches('form') ? 'submit' :
449
+ element.matches('input:not([type=button]),select,textarea') ? 'change' :
450
+ 'click';
451
+ }
452
+
453
+ let specs = api.parseTriggerSpecs(triggerSpec);
454
+ if (specs.length > 0) {
455
+ let spec = specs[0];
456
+
457
+ let handler = (evt) => {
458
+ // Prevent default for forms
459
+ if (element.matches('form') && evt.type === 'submit') {
460
+ evt.preventDefault();
461
+ }
462
+
463
+ // If this element has its own URL, ensure connection exists
464
+ if (sendUrl) {
465
+ if (!element._htmx?.wsUrl) {
466
+ getOrCreateConnection(sendUrl, element);
467
+ element._htmx = element._htmx || {};
468
+ element._htmx.wsUrl = sendUrl;
469
+ }
470
+ }
471
+
472
+ sendMessage(element, evt);
473
+ };
474
+
475
+ element.addEventListener(spec.name, handler);
476
+ element._htmx = element._htmx || {};
477
+ element._htmx.wsSendInitialized = true;
478
+ element._htmx.wsSendHandler = handler;
479
+ element._htmx.wsSendEvent = spec.name;
480
+ }
481
+ }
482
+
483
+ function cleanupElement(element) {
484
+ if (element._htmx?.wsUrl) {
485
+ decrementRef(element._htmx.wsUrl, element);
486
+ }
487
+
488
+ if (element._htmx?.wsSendHandler) {
489
+ element.removeEventListener(element._htmx.wsSendEvent, element._htmx.wsSendHandler);
490
+ }
491
+ }
492
+
493
+ // ========================================
494
+ // BACKWARD COMPATIBILITY
495
+ // ========================================
496
+
497
+ function checkLegacyAttributes(element) {
498
+ // Check for old ws-connect / ws-send attributes
499
+ if (element.hasAttribute('ws-connect') || element.hasAttribute('ws-send')) {
500
+ console.warn('HTMX WebSocket: Legacy attributes ws-connect and ws-send are deprecated. Please use hx-ws:connect/hx-ws-connect and hx-ws:send/hx-ws-send instead.');
501
+
502
+ // Map legacy attributes to new ones (prefer hyphen variant for broader compatibility)
503
+ if (element.hasAttribute('ws-connect')) {
504
+ let url = element.getAttribute('ws-connect');
505
+ if (!element.hasAttribute('hx-ws-connect')) {
506
+ element.setAttribute('hx-ws-connect', url);
507
+ }
508
+ }
509
+
510
+ if (element.hasAttribute('ws-send')) {
511
+ if (!element.hasAttribute('hx-ws-send')) {
512
+ element.setAttribute('hx-ws-send', '');
513
+ }
514
+ }
515
+ }
516
+ }
517
+
518
+ // ========================================
519
+ // EXTENSION REGISTRATION
520
+ // ========================================
521
+
522
+ htmx.registerExtension('ws', {
523
+ init: (internalAPI) => {
524
+ api = internalAPI;
525
+
526
+ // Initialize default config if not set
527
+ if (!htmx.config.websockets) {
528
+ htmx.config.websockets = {};
529
+ }
530
+ },
531
+
532
+ htmx_after_process: (element) => {
533
+ const processNode = (node) => {
534
+ // Check for legacy attributes
535
+ checkLegacyAttributes(node);
536
+
537
+ // Initialize WebSocket connection elements (check both variants)
538
+ if (hasWsAttribute(node, 'connect')) {
539
+ initializeElement(node);
540
+ }
541
+
542
+ // Initialize send elements (check both variants)
543
+ if (hasWsAttribute(node, 'send')) {
544
+ initializeSendElement(node);
545
+ }
546
+ };
547
+
548
+ // Process the element itself
549
+ processNode(element);
550
+
551
+ // Process descendants
552
+ element.querySelectorAll('[hx-ws\\:connect], [hx-ws-connect], [hx-ws\\:send], [hx-ws-send], [hx-ws], [ws-connect], [ws-send]').forEach(processNode);
553
+ },
554
+
555
+ htmx_before_cleanup: (element) => {
556
+ cleanupElement(element);
557
+ }
558
+ });
559
+
560
+ // Expose registry for testing
561
+ if (typeof window !== 'undefined' && window.htmx) {
562
+ window.htmx.ext = window.htmx.ext || {};
563
+ window.htmx.ext.ws = {
564
+ getRegistry: () => ({
565
+ clear: () => {
566
+ let entries = Array.from(connectionRegistry.values());
567
+ connectionRegistry.clear(); // Clear first to prevent reconnects
568
+
569
+ entries.forEach(entry => {
570
+ entry.refCount = 0; // Prevent pending timeouts from reconnecting
571
+ if (entry.reconnectTimer) {
572
+ clearTimeout(entry.reconnectTimer);
573
+ }
574
+ if (entry.socket) {
575
+ // Remove listeners if possible or just close
576
+ entry.socket.close();
577
+ }
578
+ entry.elements.clear();
579
+ entry.pendingRequests.clear();
580
+ });
581
+ },
582
+ get: (key) => connectionRegistry.get(key),
583
+ has: (key) => connectionRegistry.has(key),
584
+ size: connectionRegistry.size
585
+ })
586
+ };
587
+ }
588
+ })();
@@ -0,0 +1 @@
1
+ (()=>{let e;function t(t,n){let r=e.attributeValue(t,"hx-ws:"+n);if(null!=r)return r;let s=e.attributeValue(t,"hx-ws-"+n);if(null!=s)return s;if("send"===n){let n=e.attributeValue(t,"hx-ws");if(null!=n)return n}return null}function n(e,n){let r=t(e,n);return null!=r}function r(){return{reconnect:!0,reconnectDelay:1e3,reconnectMaxDelay:3e4,reconnectJitter:!0,autoConnect:!1,pauseInBackground:!0,...htmx.config.websockets||{}}}const s=new Map;function o(e,t){if(s.has(e)){let n=s.get(e);return n.refCount++,n.elements.add(t),n}let n={socket:null,refCount:1,elements:new Set([t]),reconnectAttempts:0,reconnectTimer:null,pendingRequests:new Map};return s.set(e,n),c(e,n),n}function c(t,n){let o=n.elements.values().next().value;if(!o||i(o,"htmx:before:ws:connect",{url:t}))try{n.socket=new WebSocket(t),n.socket.addEventListener("open",()=>{o&&i(o,"htmx:after:ws:connect",{url:t,socket:n.socket})}),n.socket.addEventListener("message",t=>{!function(t,n){let r;try{r=JSON.parse(n.data)}catch(e){let r=t.elements.values().next().value;return void(r&&i(r,"htmx:wsUnknownMessage",{data:n.data}))}r.channel=r.channel||"ui",r.format=r.format||"html";let s=null;r.request_id&&t.pendingRequests.has(r.request_id)?(s=t.pendingRequests.get(r.request_id).element,t.pendingRequests.delete(r.request_id)):s=t.elements.values().next().value;if(!i(s,"htmx:before:ws:message",{envelope:r,element:s}))return;"ui"===r.channel&&"html"===r.format?function(t,n){let r=(new DOMParser).parseFromString(n.payload,"text/html"),s=r.querySelectorAll("hx-partial");if(0===s.length){let r=function(t){let n=e.attributeValue(t,"hx-target");if(n)return"this"===n?t:document.querySelector(n);return t}(t);return void(r&&l(r,n.payload,t))}s.forEach(e=>{let n=e.getAttribute("id");if(!n)return;let r=document.getElementById(n);r&&l(r,e.innerHTML,t)})}(s,r):!r.channel||"audio"!==r.channel&&"json"!==r.channel&&"binary"!==r.channel?i(s,"htmx:wsUnknownMessage",{...r,element:s}):i(s,"htmx:wsMessage",{...r,element:s});i(s,"htmx:after:ws:message",{envelope:r,element:s})}(n,t)}),n.socket.addEventListener("close",()=>{if(o&&i(o,"htmx:ws:close",{url:t}),!s.has(t))return;r().reconnect&&n.refCount>0?function(e,t){let n=r(),s=t.reconnectAttempts;t.reconnectAttempts++;let o=Math.min((n.reconnectDelay||1e3)*Math.pow(2,s),n.reconnectMaxDelay||3e4);n.reconnectJitter&&(o*=.75+.5*Math.random());t.reconnectTimer=setTimeout(()=>{if(t.refCount>0){let n=t.elements.values().next().value;n&&i(n,"htmx:ws:reconnect",{url:e,attempts:s}),c(e,t)}},o)}(t,n):s.delete(t)}),n.socket.addEventListener("error",e=>{o&&i(o,"htmx:ws:error",{url:t,error:e})})}catch(e){o&&i(o,"htmx:ws:error",{url:t,error:e})}}function a(n,r){let o=t(n,"send");if(!o){let e=htmx.config.prefix||"",r=n.closest("["+e+"hx-ws\\:connect],["+e+"hx-ws-connect]");r&&(o=t(r,"connect"))}if(!o)return void console.error("No WebSocket connection found for hx-ws:send element",n);let c=s.get(o);if(!c||!c.socket||c.socket.readyState!==WebSocket.OPEN)return void i(n,"htmx:wsSendError",{url:o,error:"Connection not open"});let a=n.form||n.closest("form"),l=e.collectFormData(n,a,r.submitter);e.handleHxVals(n,l);let u={};for(let[e,t]of l)u[e]=t;let x="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){let t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}),m={type:"request",request_id:x,event:r.type,values:u,path:o};n.id&&(m.id=n.id);let h={message:m,element:n,url:o};if(i(n,"htmx:before:ws:send",h))try{c.socket.send(JSON.stringify(h.message)),c.pendingRequests.set(x,{element:n,timestamp:Date.now()}),i(n,"htmx:after:ws:send",{message:h.message,url:o})}catch(e){i(n,"htmx:wsSendError",{url:o,error:e})}}function l(t,n,r){let s=(e.attributeValue(r,"hx-swap")||htmx.config.defaultSwap).split(" ")[0];switch(s=function(e){return"before"===e?"beforebegin":"after"===e?"afterend":"prepend"===e?"afterbegin":"append"===e?"beforeend":e}(s),s){case"innerHTML":default:t.innerHTML=n;break;case"outerHTML":t.outerHTML=n;break;case"beforebegin":t.insertAdjacentHTML("beforebegin",n);break;case"afterbegin":t.insertAdjacentHTML("afterbegin",n);break;case"beforeend":t.insertAdjacentHTML("beforeend",n);break;case"afterend":t.insertAdjacentHTML("afterend",n);break;case"delete":t.remove();case"none":}htmx.process(t)}function i(e,t,n={}){return!e||htmx.trigger(e,t,n)}function u(e){e._htmx?.wsUrl&&function(e,t){if(!s.has(e))return;let n=s.get(e);n.elements.delete(t),n.refCount--,n.refCount<=0&&(n.reconnectTimer&&clearTimeout(n.reconnectTimer),n.socket&&n.socket.readyState===WebSocket.OPEN&&n.socket.close(),s.delete(e))}(e._htmx.wsUrl,e),e._htmx?.wsSendHandler&&e.removeEventListener(e._htmx.wsSendEvent,e._htmx.wsSendHandler)}htmx.registerExtension("ws",{init:t=>{e=t,htmx.config.websockets||(htmx.config.websockets={})},htmx_after_process:s=>{const c=s=>{!function(e){if(e.hasAttribute("ws-connect")||e.hasAttribute("ws-send")){if(console.warn("HTMX WebSocket: Legacy attributes ws-connect and ws-send are deprecated. Please use hx-ws:connect/hx-ws-connect and hx-ws:send/hx-ws-send instead."),e.hasAttribute("ws-connect")){let t=e.getAttribute("ws-connect");e.hasAttribute("hx-ws-connect")||e.setAttribute("hx-ws-connect",t)}e.hasAttribute("ws-send")&&(e.hasAttribute("hx-ws-send")||e.setAttribute("hx-ws-send",""))}}(s),n(s,"connect")&&function(n){if(n._htmx?.wsInitialized)return;let s=t(n,"connect");if(!s)return;n._htmx=n._htmx||{},n._htmx.wsInitialized=!0;let c=r(),a=e.attributeValue(n,"hx-trigger");if(a||!0!==c.autoConnect){if(a){let t=e.parseTriggerSpecs(a);if(t.length>0){let e=t[0];"load"===e.name?(o(s,n),n._htmx=n._htmx||{},n._htmx.wsUrl=s):n.addEventListener(e.name,()=>{n._htmx?.wsUrl||(o(s,n),n._htmx=n._htmx||{},n._htmx.wsUrl=s)},{once:!0})}}}else o(s,n),n._htmx=n._htmx||{},n._htmx.wsUrl=s}(s),n(s,"send")&&function(n){if(n._htmx?.wsSendInitialized)return;let r=t(n,"send"),s=e.attributeValue(n,"hx-trigger");s||(s=n.matches("form")?"submit":n.matches("input:not([type=button]),select,textarea")?"change":"click");let c=e.parseTriggerSpecs(s);if(c.length>0){let e=c[0],t=e=>{n.matches("form")&&"submit"===e.type&&e.preventDefault(),r&&(n._htmx?.wsUrl||(o(r,n),n._htmx=n._htmx||{},n._htmx.wsUrl=r)),a(n,e)};n.addEventListener(e.name,t),n._htmx=n._htmx||{},n._htmx.wsSendInitialized=!0,n._htmx.wsSendHandler=t,n._htmx.wsSendEvent=e.name}}(s)};c(s),s.querySelectorAll("[hx-ws\\:connect], [hx-ws-connect], [hx-ws\\:send], [hx-ws-send], [hx-ws], [ws-connect], [ws-send]").forEach(c)},htmx_before_cleanup:e=>{u(e)}}),"undefined"!=typeof window&&window.htmx&&(window.htmx.ext=window.htmx.ext||{},window.htmx.ext.ws={getRegistry:()=>({clear:()=>{let e=Array.from(s.values());s.clear(),e.forEach(e=>{e.refCount=0,e.reconnectTimer&&clearTimeout(e.reconnectTimer),e.socket&&e.socket.close(),e.elements.clear(),e.pendingRequests.clear()})},get:e=>s.get(e),has:e=>s.has(e),size:s.size})})})();
@@ -0,0 +1 @@
1
+ {"version":3,"names":["api","getWsAttribute","element","attrName","colonValue","attributeValue","hyphenValue","plainValue","hasWsAttribute","value","getConfig","reconnect","reconnectDelay","reconnectMaxDelay","reconnectJitter","autoConnect","pauseInBackground","htmx","config","websockets","connectionRegistry","Map","getOrCreateConnection","url","has","entry","get","refCount","elements","add","socket","Set","reconnectAttempts","reconnectTimer","pendingRequests","set","createWebSocket","firstElement","values","next","triggerEvent","WebSocket","addEventListener","event","envelope","JSON","parse","data","e","channel","format","targetElement","request_id","delete","doc","DOMParser","parseFromString","payload","partials","querySelectorAll","length","target","targetSelector","document","querySelector","resolveTarget","swapContent","forEach","partial","targetId","getAttribute","getElementById","innerHTML","handleHtmlMessage","handleMessage","attempts","delay","Math","min","pow","random","setTimeout","scheduleReconnect","error","sendMessage","prefix","ancestor","closest","console","readyState","OPEN","form","body","collectFormData","submitter","handleHxVals","key","requestId","replace","c","r","toString","message","type","path","id","detail","send","stringify","timestamp","Date","now","content","sourceElement","style","defaultSwap","split","normalizeSwapStyle","outerHTML","insertAdjacentHTML","remove","process","eventName","trigger","cleanupElement","_htmx","wsUrl","clearTimeout","close","decrementRef","wsSendHandler","removeEventListener","wsSendEvent","registerExtension","init","internalAPI","htmx_after_process","processNode","node","hasAttribute","warn","setAttribute","checkLegacyAttributes","wsInitialized","connectUrl","triggerSpec","specs","parseTriggerSpecs","spec","name","once","initializeElement","wsSendInitialized","sendUrl","matches","handler","evt","preventDefault","initializeSendElement","htmx_before_cleanup","window","ext","ws","getRegistry","clear","entries","Array","from","size"],"sources":["dist/ext/hx-ws.js"],"mappings":"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","ignoreList":[]}
package/dist/htmx.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ export interface HtmxConfig {
2
+ version: string;
3
+ logAll: boolean;
4
+ prefix: string;
5
+ transitions: boolean;
6
+ history: boolean;
7
+ historyReload: boolean;
8
+ mode: 'same-origin' | 'cors' | 'no-cors';
9
+ defaultSwap: string;
10
+ indicatorClass: string;
11
+ requestClass: string;
12
+ includeIndicatorCSS: boolean;
13
+ defaultTimeout: number;
14
+ inlineScriptNonce: string;
15
+ inlineStyleNonce: string;
16
+ extensions: string;
17
+ morphIgnore: string[];
18
+ noSwap: number[];
19
+ implicitInheritance: boolean;
20
+ metaCharacter?: string;
21
+ streams?: {
22
+ reconnect: boolean;
23
+ reconnectMaxAttempts: number;
24
+ reconnectDelay: number;
25
+ reconnectMaxDelay: number;
26
+ reconnectJitter: number;
27
+ pauseInBackground: boolean;
28
+ };
29
+ }
30
+
31
+ export interface Htmx {
32
+ config: HtmxConfig;
33
+ ajax(verb: string, path: string, context?: any): Promise<void>;
34
+ find(selector: string): Element | null;
35
+ find(elt: Element, selector: string): Element | null;
36
+ findAll(selector: string): Element[];
37
+ findAll(elt: Element, selector: string): Element[];
38
+ on(event: string, handler: (evt: Event) => void): void;
39
+ on(target: string | Element, event: string, handler: (evt: Event) => void): void;
40
+ onLoad(callback: (elt: Element) => void): void;
41
+ process(elt: Element): void;
42
+ registerExtension(name: string, ext: any): boolean;
43
+ trigger(elt: Element | string, event: string, detail?: any): boolean;
44
+ timeout(ms: number): Promise<void>;
45
+ parseInterval(str: string): number;
46
+ forEvent(event: string, timeout?: number): Promise<Event | null>;
47
+ swap(target: Element | string, content: string, swapSpec: any): void;
48
+ takeClass(elt: Element, className: string, container?: Element): void;
49
+ }
50
+
51
+ declare const htmx: Htmx;
52
+ export default htmx;