Skip to content

Commit

Permalink
Remove legacy WS/SSE code (bigskysoftware#2095)
Browse files Browse the repository at this point in the history
* apply updated patch with legacy WS/SSE removal

* remove legace WS/SSE from the test server also

* remove sse mention from getTriggerSpec()

* clean up sse.js implementation after removal of hx-sse
  • Loading branch information
Renerick authored Dec 14, 2023
1 parent 63e4ef6 commit 2325637
Show file tree
Hide file tree
Showing 24 changed files with 28 additions and 833 deletions.
62 changes: 10 additions & 52 deletions src/ext/sse.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,38 +72,6 @@ This extension adds support for Server Sent Events to htmx. See /www/extensions
return new EventSource(url, { withCredentials: true });
}

function splitOnWhitespace(trigger) {
return trigger.trim().split(/\s+/);
}

function getLegacySSEURL(elt) {
var legacySSEValue = api.getAttributeValue(elt, "hx-sse");
if (legacySSEValue) {
var values = splitOnWhitespace(legacySSEValue);
for (var i = 0; i < values.length; i++) {
var value = values[i].split(/:(.+)/);
if (value[0] === "connect") {
return value[1];
}
}
}
}

function getLegacySSESwaps(elt) {
var legacySSEValue = api.getAttributeValue(elt, "hx-sse");
var returnArr = [];
if (legacySSEValue != null) {
var values = splitOnWhitespace(legacySSEValue);
for (var i = 0; i < values.length; i++) {
var value = values[i].split(/:(.+)/);
if (value[0] === "swap") {
returnArr.push(value[1]);
}
}
}
return returnArr;
}

/**
* registerSSE looks for attributes that can contain sse events, right
* now hx-trigger and sse-swap and adds listeners based on these attributes too
Expand All @@ -127,11 +95,7 @@ This extension adds support for Server Sent Events to htmx. See /www/extensions
queryAttributeOnThisOrChildren(elt, "sse-swap").forEach(function(child) {

var sseSwapAttr = api.getAttributeValue(child, "sse-swap");
if (sseSwapAttr) {
var sseEventNames = sseSwapAttr.split(",");
} else {
var sseEventNames = getLegacySSESwaps(child);
}
var sseEventNames = sseSwapAttr.split(",");

for (var i = 0; i < sseEventNames.length; i++) {
var sseEventName = sseEventNames[i].trim();
Expand Down Expand Up @@ -170,19 +134,24 @@ This extension adds support for Server Sent Events to htmx. See /www/extensions
if (sseEventName.slice(0, 4) != "sse:") {
return;
}

// remove the sse: prefix from here on out
sseEventName = sseEventName.substr(4);

var listener = function() {
var listener = function(event) {
if (maybeCloseSSESource(sourceElement)) {
return
}

if (!api.bodyContains(child)) {
source.removeEventListener(sseEventName, listener);
}

// Trigger events to be handled by the rest of htmx
htmx.trigger(child, sseEventName, event);
htmx.trigger(child, "htmx:sseMessage", event);
}

// Register the new listener
api.getInternalData(elt).sseEventListener = listener;
source.addEventListener(sseEventName.slice(4), listener);
});
}

Expand All @@ -209,17 +178,6 @@ This extension adds support for Server Sent Events to htmx. See /www/extensions

ensureEventSource(child, sseURL, retryCount);
});

// handle legacy sse, remove for HTMX2
queryAttributeOnThisOrChildren(elt, "hx-sse").forEach(function(child) {
var sseURL = getLegacySSEURL(child);
if (sseURL == null) {
return;
}

ensureEventSource(child, sseURL, retryCount);
});

}

function ensureEventSource(elt, url, retryCount) {
Expand Down
249 changes: 3 additions & 246 deletions src/htmx.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,6 @@ return (function () {
},
parseInterval:parseInterval,
_:internalEval,
createEventSource: function(url){
return new EventSource(url, {withCredentials:true})
},
createWebSocket: function(url){
var sock = new WebSocket(url, []);
sock.binaryType = htmx.config.wsBinaryType;
return sock;
},
version: "1.9.10"
};

Expand Down Expand Up @@ -948,12 +940,6 @@ return (function () {
if (internalData.timeout) {
clearTimeout(internalData.timeout);
}
if (internalData.webSocket) {
internalData.webSocket.close();
}
if (internalData.sseEventSource) {
internalData.sseEventSource.close();
}
if (internalData.listenerInfos) {
forEach(internalData.listenerInfos, function (info) {
if (info.on) {
Expand Down Expand Up @@ -1272,8 +1258,6 @@ return (function () {
every.eventFilter = eventFilter;
}
triggerSpecs.push(every);
} else if (trigger.indexOf("sse:") === 0) {
triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)});
} else {
var triggerSpec = {trigger: trigger};
var eventFilter = maybeGenerateConditional(elt, tokens, "event");
Expand Down Expand Up @@ -1581,222 +1565,6 @@ return (function () {
}
}

//====================================================================
// Web Sockets
//====================================================================

function processWebSocketInfo(elt, nodeData, info) {
var values = splitOnWhitespace(info);
for (var i = 0; i < values.length; i++) {
var value = values[i].split(/:(.+)/);
if (value[0] === "connect") {
ensureWebSocket(elt, value[1], 0);
}
if (value[0] === "send") {
processWebSocketSend(elt);
}
}
}

function ensureWebSocket(elt, wssSource, retryCount) {
if (!bodyContains(elt)) {
return; // stop ensuring websocket connection when socket bearing element ceases to exist
}

if (wssSource.indexOf("/") == 0) { // complete absolute paths only
var base_part = location.hostname + (location.port ? ':'+location.port: '');
if (location.protocol == 'https:') {
wssSource = "wss://" + base_part + wssSource;
} else if (location.protocol == 'http:') {
wssSource = "ws://" + base_part + wssSource;
}
}
var socket = htmx.createWebSocket(wssSource);
socket.onerror = function (e) {
triggerErrorEvent(elt, "htmx:wsError", {error:e, socket:socket});
maybeCloseWebSocketSource(elt);
};

socket.onclose = function (e) {
if ([1006, 1012, 1013].indexOf(e.code) >= 0) { // Abnormal Closure/Service Restart/Try Again Later
var delay = getWebSocketReconnectDelay(retryCount);
setTimeout(function() {
ensureWebSocket(elt, wssSource, retryCount+1); // creates a websocket with a new timeout
}, delay);
}
};
socket.onopen = function (e) {
retryCount = 0;
}

getInternalData(elt).webSocket = socket;
socket.addEventListener('message', function (event) {
if (maybeCloseWebSocketSource(elt)) {
return;
}

var response = event.data;
withExtensions(elt, function(extension){
response = extension.transformResponse(response, null, elt);
});

var settleInfo = makeSettleInfo(elt);
var fragment = makeFragment(response);
var children = toArray(fragment.children);
for (var i = 0; i < children.length; i++) {
var child = children[i];
oobSwap(getAttributeValue(child, "hx-swap-oob") || "true", child, settleInfo);
}

settleImmediately(settleInfo.tasks);
});
}

function maybeCloseWebSocketSource(elt) {
if (!bodyContains(elt)) {
getInternalData(elt).webSocket.close();
return true;
}
}

function processWebSocketSend(elt) {
var webSocketSourceElt = getClosestMatch(elt, function (parent) {
return getInternalData(parent).webSocket != null;
});
if (webSocketSourceElt) {
elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) {
var webSocket = getInternalData(webSocketSourceElt).webSocket;
var headers = getHeaders(elt, webSocketSourceElt);
var results = getInputValues(elt, 'post');
var errors = results.errors;
var rawParameters = results.values;
var expressionVars = getExpressionVars(elt);
var allParameters = mergeObjects(rawParameters, expressionVars);
var filteredParameters = filterValues(allParameters, elt);
filteredParameters['HEADERS'] = headers;
if (errors && errors.length > 0) {
triggerEvent(elt, 'htmx:validation:halted', errors);
return;
}
webSocket.send(JSON.stringify(filteredParameters));
if(shouldCancel(evt, elt)){
evt.preventDefault();
}
});
} else {
triggerErrorEvent(elt, "htmx:noWebSocketSourceError");
}
}

function getWebSocketReconnectDelay(retryCount) {
var delay = htmx.config.wsReconnectDelay;
if (typeof delay === 'function') {
// @ts-ignore
return delay(retryCount);
}
if (delay === 'full-jitter') {
var exp = Math.min(retryCount, 6);
var maxDelay = 1000 * Math.pow(2, exp);
return maxDelay * Math.random();
}
logError('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"');
}

//====================================================================
// Server Sent Events
//====================================================================

function processSSEInfo(elt, nodeData, info) {
var values = splitOnWhitespace(info);
for (var i = 0; i < values.length; i++) {
var value = values[i].split(/:(.+)/);
if (value[0] === "connect") {
processSSESource(elt, value[1]);
}

if ((value[0] === "swap")) {
processSSESwap(elt, value[1])
}
}
}

function processSSESource(elt, sseSrc) {
var source = htmx.createEventSource(sseSrc);
source.onerror = function (e) {
triggerErrorEvent(elt, "htmx:sseError", {error:e, source:source});
maybeCloseSSESource(elt);
};
getInternalData(elt).sseEventSource = source;
}

function processSSESwap(elt, sseEventName) {
var sseSourceElt = getClosestMatch(elt, hasEventSource);
if (sseSourceElt) {
var sseEventSource = getInternalData(sseSourceElt).sseEventSource;
var sseListener = function (event) {
if (maybeCloseSSESource(sseSourceElt)) {
return;
}
if (!bodyContains(elt)) {
sseEventSource.removeEventListener(sseEventName, sseListener);
return;
}

///////////////////////////
// TODO: merge this code with AJAX and WebSockets code in the future.

var response = event.data;
withExtensions(elt, function(extension){
response = extension.transformResponse(response, null, elt);
});

var swapSpec = getSwapSpecification(elt)
var target = getTarget(elt)
var settleInfo = makeSettleInfo(elt);

selectAndSwap(swapSpec.swapStyle, target, elt, response, settleInfo)
settleImmediately(settleInfo.tasks)
triggerEvent(elt, "htmx:sseMessage", event)
};

getInternalData(elt).sseListener = sseListener;
sseEventSource.addEventListener(sseEventName, sseListener);
} else {
triggerErrorEvent(elt, "htmx:noSSESourceError");
}
}

function processSSETrigger(elt, handler, sseEventName) {
var sseSourceElt = getClosestMatch(elt, hasEventSource);
if (sseSourceElt) {
var sseEventSource = getInternalData(sseSourceElt).sseEventSource;
var sseListener = function () {
if (!maybeCloseSSESource(sseSourceElt)) {
if (bodyContains(elt)) {
handler(elt);
} else {
sseEventSource.removeEventListener(sseEventName, sseListener);
}
}
};
getInternalData(elt).sseListener = sseListener;
sseEventSource.addEventListener(sseEventName, sseListener);
} else {
triggerErrorEvent(elt, "htmx:noSSESourceError");
}
}

function maybeCloseSSESource(elt) {
if (!bodyContains(elt)) {
getInternalData(elt).sseEventSource.close();
return true;
}
}

function hasEventSource(node) {
return getInternalData(node).sseEventSource != null;
}

//====================================================================

function loadImmediately(elt, handler, nodeData, delay) {
Expand Down Expand Up @@ -1836,9 +1604,7 @@ return (function () {
}

function addTriggerHandler(elt, triggerSpec, nodeData, handler) {
if (triggerSpec.sseEvent) {
processSSETrigger(elt, handler, triggerSpec.sseEvent);
} else if (triggerSpec.trigger === "revealed") {
if (triggerSpec.trigger === "revealed") {
initScrollHandler();
addEventListener(elt, handler, nodeData, triggerSpec);
maybeReveal(elt);
Expand Down Expand Up @@ -1947,8 +1713,8 @@ return (function () {
function findElementsToProcess(elt) {
if (elt.querySelectorAll) {
var boostedSelector = ", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]";
var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit'], [hx-sse], [data-hx-sse], [hx-ws]," +
" [data-hx-ws], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]");
var results = elt.querySelectorAll(VERB_SELECTOR + boostedSelector + ", form, [type='submit']," +
" [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]");
return results;
} else {
return [];
Expand Down Expand Up @@ -2088,15 +1854,6 @@ return (function () {
initButtonTracking(elt)
}

var sseInfo = getAttributeValue(elt, 'hx-sse');
if (sseInfo) {
processSSEInfo(elt, nodeData, sseInfo);
}

var wsInfo = getAttributeValue(elt, 'hx-ws');
if (wsInfo) {
processWebSocketInfo(elt, nodeData, wsInfo);
}
triggerEvent(elt, "htmx:afterProcessNode");
}
}
Expand Down
Loading

0 comments on commit 2325637

Please sign in to comment.