mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-10-03 07:45:21 +00:00
revert settle attribute swapping so internals work + hx-ws tests (ugh)
This commit is contained in:
parent
7036557cba
commit
51697abff6
47
dist/htmx.js
vendored
47
dist/htmx.js
vendored
@ -346,13 +346,11 @@ return (function () {
|
|||||||
var target = getDocument().getElementById(child.id);
|
var target = getDocument().getElementById(child.id);
|
||||||
if (target) {
|
if (target) {
|
||||||
var fragment;
|
var fragment;
|
||||||
if (isInlineSwap(oobValue, target)) {
|
fragment = getDocument().createDocumentFragment();
|
||||||
fragment = getDocument().createDocumentFragment();
|
fragment.appendChild(child); // pulls the child out of the existing fragment
|
||||||
fragment.appendChild(child);
|
if (!isInlineSwap(oobValue, target)) {
|
||||||
} else {
|
fragment = child; // if this is not an inline swap, we use the content of the node, not the node itself
|
||||||
fragment = child;
|
|
||||||
}
|
}
|
||||||
fragment.appendChild(child);
|
|
||||||
swap(oobValue, target, target, fragment, settleInfo);
|
swap(oobValue, target, target, fragment, settleInfo);
|
||||||
} else {
|
} else {
|
||||||
child.parentNode.removeChild(child);
|
child.parentNode.removeChild(child);
|
||||||
@ -370,27 +368,26 @@ return (function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAttributes(parentNode, fragment, settleInfo) {
|
|
||||||
forEach(fragment.querySelectorAll("[id]"), function (newNode) {
|
|
||||||
var oldNode = parentNode.querySelector(newNode.tagName + "[id=" + newNode.id + "]")
|
|
||||||
if (oldNode) {
|
|
||||||
var newAttributes = newNode.cloneNode();
|
|
||||||
cloneAttributes(newNode, oldNode);
|
|
||||||
settleInfo.tasks.push(function () {
|
|
||||||
cloneAttributes(newNode, newAttributes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
||||||
handleAttributes(parentNode, fragment, settleInfo);
|
|
||||||
while(fragment.childNodes.length > 0){
|
while(fragment.childNodes.length > 0){
|
||||||
var child = fragment.firstChild;
|
var child = fragment.firstChild;
|
||||||
parentNode.insertBefore(child, insertBefore);
|
parentNode.insertBefore(child, insertBefore);
|
||||||
if (child.nodeType !== Node.TEXT_NODE) {
|
if (child.nodeType !== Node.TEXT_NODE) {
|
||||||
triggerEvent(child, 'load.htmx', {});
|
var newAttributes = null;
|
||||||
processNode(child);
|
if (child.id) {
|
||||||
|
var originalNode = parentNode.querySelector(child.tagName + "[id=" + child.id + "]");
|
||||||
|
if (originalNode && originalNode !== parentNode) {
|
||||||
|
newAttributes = child.cloneNode();
|
||||||
|
cloneAttributes(child, originalNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settleInfo.tasks.push(function(){
|
||||||
|
if (newAttributes) {
|
||||||
|
cloneAttributes(child, newAttributes);
|
||||||
|
}
|
||||||
|
processNode(child);
|
||||||
|
triggerEvent(child, 'load.htmx', {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -757,10 +754,6 @@ return (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processSSESource(elt, sseSrc) {
|
function processSSESource(elt, sseSrc) {
|
||||||
var detail = {
|
|
||||||
config:{withCredentials: true}
|
|
||||||
};
|
|
||||||
triggerEvent(elt, "initSSE.htmx", detail);
|
|
||||||
var source = new EventSource(sseSrc, detail.config);
|
var source = new EventSource(sseSrc, detail.config);
|
||||||
source.onerror = function (e) {
|
source.onerror = function (e) {
|
||||||
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
||||||
@ -1494,7 +1487,7 @@ return (function () {
|
|||||||
function getMetaConfig() {
|
function getMetaConfig() {
|
||||||
var element = getDocument().querySelector('meta[name="htmx-config"]');
|
var element = getDocument().querySelector('meta[name="htmx-config"]');
|
||||||
if (element) {
|
if (element) {
|
||||||
return JSON.parse(element.content);
|
return eval(element.content);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
2
dist/htmx.min.js
vendored
2
dist/htmx.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/htmx.min.js.gz
vendored
BIN
dist/htmx.min.js.gz
vendored
Binary file not shown.
55
src/htmx.js
55
src/htmx.js
@ -368,23 +368,26 @@ return (function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAttributes(parentNode, fragment, settleInfo) {
|
||||||
|
forEach(fragment.querySelectorAll("[id]"), function (newNode) {
|
||||||
|
var oldNode = parentNode.querySelector(newNode.tagName + "[id=" + newNode.id + "]")
|
||||||
|
if (oldNode && oldNode !== parentNode) {
|
||||||
|
var newAttributes = newNode.cloneNode();
|
||||||
|
cloneAttributes(newNode, oldNode);
|
||||||
|
settleInfo.tasks.push(function () {
|
||||||
|
cloneAttributes(newNode, newAttributes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
||||||
|
handleAttributes(parentNode, fragment, settleInfo);
|
||||||
while(fragment.childNodes.length > 0){
|
while(fragment.childNodes.length > 0){
|
||||||
var child = fragment.firstChild;
|
var child = fragment.firstChild;
|
||||||
parentNode.insertBefore(child, insertBefore);
|
parentNode.insertBefore(child, insertBefore);
|
||||||
if (child.nodeType !== Node.TEXT_NODE) {
|
if (child.nodeType !== Node.TEXT_NODE) {
|
||||||
var newAttributes = null;
|
|
||||||
if (child.id) {
|
|
||||||
var originalNode = parentNode.querySelector(child.tagName + "[id=" + child.id + "]");
|
|
||||||
if (originalNode && originalNode !== parentNode) {
|
|
||||||
newAttributes = child.cloneNode();
|
|
||||||
cloneAttributes(child, originalNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
settleInfo.tasks.push(function(){
|
settleInfo.tasks.push(function(){
|
||||||
if (newAttributes) {
|
|
||||||
cloneAttributes(child, newAttributes);
|
|
||||||
}
|
|
||||||
processNode(child);
|
processNode(child);
|
||||||
triggerEvent(child, 'load.htmx', {});
|
triggerEvent(child, 'load.htmx', {});
|
||||||
});
|
});
|
||||||
@ -663,21 +666,17 @@ return (function () {
|
|||||||
var values = info.split(",");
|
var values = info.split(",");
|
||||||
for (var i = 0; i < values.length; i++) {
|
for (var i = 0; i < values.length; i++) {
|
||||||
var value = removeWhiteSpace(values[i]);
|
var value = removeWhiteSpace(values[i]);
|
||||||
if (value.indexOf("source:") === 0) {
|
if (value.indexOf("source ") === 0) {
|
||||||
processWebSocketSource(elt, value.substr(7));
|
processWebSocketSource(elt, value.substr(7));
|
||||||
}
|
}
|
||||||
if (value.indexOf("send:") === 0) {
|
if (value === "send") {
|
||||||
processWebSocketSend(elt, value.substr(5));
|
processWebSocketSend(elt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processWebSocketSource(elt, wssSource) {
|
function processWebSocketSource(elt, wssSource) {
|
||||||
var detail = {
|
var socket = htmx.createWebSocket(wssSource);
|
||||||
protocols:[]
|
|
||||||
};
|
|
||||||
triggerEvent(elt, "initWebSocket.htmx", detail);
|
|
||||||
var socket = new WebSocket("wss:" + wssSource, detail.protocols);
|
|
||||||
socket.onerror = function (e) {
|
socket.onerror = function (e) {
|
||||||
triggerErrorEvent(elt, "wsError.htmx", {error:e, socket:socket});
|
triggerErrorEvent(elt, "wsError.htmx", {error:e, socket:socket});
|
||||||
maybeCloseWebSocketSource(elt);
|
maybeCloseWebSocketSource(elt);
|
||||||
@ -712,13 +711,13 @@ return (function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processWebSocketSend(elt, eventName) {
|
function processWebSocketSend(elt) {
|
||||||
var webSocketSourceElt = getClosestMatch(elt, function (parent) {
|
var webSocketSourceElt = getClosestMatch(elt, function (parent) {
|
||||||
return getInternalData(parent).webSocket != null;
|
return getInternalData(parent).webSocket != null;
|
||||||
});
|
});
|
||||||
if (webSocketSourceElt) {
|
if (webSocketSourceElt) {
|
||||||
var webSocket = getInternalData(webSocketSourceElt).webSocket;
|
var webSocket = getInternalData(webSocketSourceElt).webSocket;
|
||||||
elt.addEventListener(eventName, function (evt) {
|
elt.addEventListener(getTriggerSpecs(elt)[0].trigger, function (evt) {
|
||||||
var headers = getHeaders(elt, webSocketSourceElt, null, elt);
|
var headers = getHeaders(elt, webSocketSourceElt, null, elt);
|
||||||
var rawParameters = getInputValues(elt, 'post');
|
var rawParameters = getInputValues(elt, 'post');
|
||||||
var filteredParameters = filterValues(rawParameters, elt);
|
var filteredParameters = filterValues(rawParameters, elt);
|
||||||
@ -754,11 +753,7 @@ return (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processSSESource(elt, sseSrc) {
|
function processSSESource(elt, sseSrc) {
|
||||||
var detail = {
|
var source = htmx.createEventSource(sseSrc);
|
||||||
config:{withCredentials: true}
|
|
||||||
};
|
|
||||||
triggerEvent(elt, "initSSE.htmx", detail);
|
|
||||||
var source = new EventSource(sseSrc, detail.config);
|
|
||||||
source.onerror = function (e) {
|
source.onerror = function (e) {
|
||||||
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
||||||
maybeCloseSSESource(elt);
|
maybeCloseSSESource(elt);
|
||||||
@ -1543,7 +1538,13 @@ return (function () {
|
|||||||
includeIndicatorStyles:true
|
includeIndicatorStyles:true
|
||||||
},
|
},
|
||||||
parseInterval:parseInterval,
|
parseInterval:parseInterval,
|
||||||
_:internalEval
|
_:internalEval,
|
||||||
|
createEventSource: function(url){
|
||||||
|
return new EventSource(url, {withCredentials:true})
|
||||||
|
},
|
||||||
|
createWebSocket: function(url){
|
||||||
|
return new WebSocket(url, []);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)()
|
)()
|
||||||
|
51
test/attributes/hx-ws.js
Normal file
51
test/attributes/hx-ws.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
describe("hx-ws attribute", function() {
|
||||||
|
|
||||||
|
function mockWebsocket() {
|
||||||
|
var listener;
|
||||||
|
var lastSent;
|
||||||
|
var mockSocket = {
|
||||||
|
addEventListener : function(message, l) {
|
||||||
|
listener = l;
|
||||||
|
},
|
||||||
|
write : function(content) {
|
||||||
|
return listener({data:content});
|
||||||
|
},
|
||||||
|
send : function(data) {
|
||||||
|
lastSent = data;
|
||||||
|
},
|
||||||
|
getLastSent : function() {
|
||||||
|
return lastSent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return mockSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
this.server = makeServer();
|
||||||
|
var socket = mockWebsocket();
|
||||||
|
this.socket = socket;
|
||||||
|
clearWorkArea();
|
||||||
|
htmx.createWebSocket = function(){ return socket };
|
||||||
|
});
|
||||||
|
afterEach(function () {
|
||||||
|
this.server.restore();
|
||||||
|
clearWorkArea();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles a basic call back', function () {
|
||||||
|
var div = make('<div hx-ws="source:wss:/foo"><div id="d1">div1</div><div id="d2">div2</div></div>');
|
||||||
|
this.socket.write("<div id=\"d1\">replaced</div>")
|
||||||
|
byId("d1").innerHTML.should.equal("replaced");
|
||||||
|
byId("d2").innerHTML.should.equal("div2");
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles a basic send', function () {
|
||||||
|
var div = make('<div hx-ws="source:wss:/foo"><div hx-ws="send" id="d1">div1</div></div>');
|
||||||
|
byId("d1").click();
|
||||||
|
var lastSent = this.socket.getLastSent();
|
||||||
|
var data = JSON.parse(lastSent);
|
||||||
|
data.HEADERS["X-HX-Request"].should.equal("true");
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -305,6 +305,19 @@ describe("Core htmx AJAX Tests", function(){
|
|||||||
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
|
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('properly settles attributes on interior elements', function(done)
|
||||||
|
{
|
||||||
|
this.server.respondWith("GET", "/test", "<div hx-get='/test'><div foo='bar' id='d1'></div></div>");
|
||||||
|
var div = make("<div hx-get='/test' hx-swap='outerHTML settle:10ms'><div id='d1'></div></div>");
|
||||||
|
div.click();
|
||||||
|
this.server.respond();
|
||||||
|
should.equal(byId("d1").getAttribute("foo"), null);
|
||||||
|
setTimeout(function () {
|
||||||
|
should.equal(byId("d1").getAttribute("foo"), "bar");
|
||||||
|
done();
|
||||||
|
}, 20);
|
||||||
|
});
|
||||||
|
|
||||||
it('properly handles checkbox inputs', function()
|
it('properly handles checkbox inputs', function()
|
||||||
{
|
{
|
||||||
var values;
|
var values;
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
<script src="attributes/hx-swap.js"></script>
|
<script src="attributes/hx-swap.js"></script>
|
||||||
<script src="attributes/hx-target.js"></script>
|
<script src="attributes/hx-target.js"></script>
|
||||||
<script src="attributes/hx-trigger.js"></script>
|
<script src="attributes/hx-trigger.js"></script>
|
||||||
|
<script src="attributes/hx-ws.js"></script>
|
||||||
|
|
||||||
<!-- extension tests -->
|
<!-- extension tests -->
|
||||||
<script src="../src/ext/rails-method.js"></script>
|
<script src="../src/ext/rails-method.js"></script>
|
||||||
|
@ -8,24 +8,25 @@ title: </> htmx - hx-ws
|
|||||||
The `hx-ws` allows you to work with [Web Sockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)
|
The `hx-ws` allows you to work with [Web Sockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)
|
||||||
directly from HTML. The value of the attribute can be one or more of the following, separated by commas:
|
directly from HTML. The value of the attribute can be one or more of the following, separated by commas:
|
||||||
|
|
||||||
* `source:<url>` - A URL to establish an `WebSocket` against (NB: do not include the `wss:` protocol prefix)
|
* `source <url>` - A URL to establish an `WebSocket` against (NB: include the `wss:` protocol prefix)
|
||||||
* `send:<event_name>` - Sends a message to the nearest websocket
|
* `send` - Sends a message to the nearest websocket based on the trigger value for the element (either the natural event
|
||||||
|
of the event specified by [`hx-trigger`])
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div hx-ws="source:/chatroom">
|
<div hx-ws="source wss:/chatroom">
|
||||||
<div id="chat_room">
|
<div id="chat_room">
|
||||||
...
|
...
|
||||||
</div>
|
</div>
|
||||||
<form hx-ws="send:submit">
|
<form hx-ws="send">
|
||||||
<input name="chat_message">
|
<input name="chat_message">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
This example establishes a WebSocket to the `chatroom` end point. Content that is send down from the websocket will
|
This example establishes a WebSocket to the `chatroom` end point. Content that is send down from the websocket will
|
||||||
be parsed as HTML and swapped in by the `id` property, similar to [Out of Band Swaps](/attributes/hx-swap-oob).
|
be parsed as HTML and swapped in by the `id` property, using the same logis as [Out of Band Swaps](/attributes/hx-swap-oob).
|
||||||
|
|
||||||
The form uses the `send:` syntax to indicate that when it is submitted, the form values should be serialized as JSON
|
The form uses the `send:` syntax to indicate that when it is submitted, the form values should be serialized as JSON
|
||||||
and send to the nearest enclosing `WebSocket`.
|
and send to the nearest enclosing `WebSocket`.
|
||||||
|
@ -118,13 +118,6 @@ This event is triggered when htmx handles a history restoration action
|
|||||||
* `detail.path` - the path and query of the page being restored
|
* `detail.path` - the path and query of the page being restored
|
||||||
* `detail.historyElt` - the history element being restored into
|
* `detail.historyElt` - the history element being restored into
|
||||||
|
|
||||||
### <a name="initSSE.htmx"></a> Event - [`initSSE.htmx`](#initSSE.htmx)
|
|
||||||
|
|
||||||
This event is triggered when htmx initializes a new SSE source. It can be used
|
|
||||||
to [configure the source](https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource).
|
|
||||||
|
|
||||||
Note that by default `withCredentials` will be set to `true` in the configuration.
|
|
||||||
|
|
||||||
##### Details
|
##### Details
|
||||||
|
|
||||||
* `detail.config` - the config that will be passed to the `EventSource` contstructor
|
* `detail.config` - the config that will be passed to the `EventSource` contstructor
|
||||||
|
@ -346,13 +346,11 @@ return (function () {
|
|||||||
var target = getDocument().getElementById(child.id);
|
var target = getDocument().getElementById(child.id);
|
||||||
if (target) {
|
if (target) {
|
||||||
var fragment;
|
var fragment;
|
||||||
if (isInlineSwap(oobValue, target)) {
|
fragment = getDocument().createDocumentFragment();
|
||||||
fragment = getDocument().createDocumentFragment();
|
fragment.appendChild(child); // pulls the child out of the existing fragment
|
||||||
fragment.appendChild(child);
|
if (!isInlineSwap(oobValue, target)) {
|
||||||
} else {
|
fragment = child; // if this is not an inline swap, we use the content of the node, not the node itself
|
||||||
fragment = child;
|
|
||||||
}
|
}
|
||||||
fragment.appendChild(child);
|
|
||||||
swap(oobValue, target, target, fragment, settleInfo);
|
swap(oobValue, target, target, fragment, settleInfo);
|
||||||
} else {
|
} else {
|
||||||
child.parentNode.removeChild(child);
|
child.parentNode.removeChild(child);
|
||||||
@ -370,27 +368,26 @@ return (function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAttributes(parentNode, fragment, settleInfo) {
|
|
||||||
forEach(fragment.querySelectorAll("[id]"), function (newNode) {
|
|
||||||
var oldNode = parentNode.querySelector(newNode.tagName + "[id=" + newNode.id + "]")
|
|
||||||
if (oldNode) {
|
|
||||||
var newAttributes = newNode.cloneNode();
|
|
||||||
cloneAttributes(newNode, oldNode);
|
|
||||||
settleInfo.tasks.push(function () {
|
|
||||||
cloneAttributes(newNode, newAttributes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
||||||
handleAttributes(parentNode, fragment, settleInfo);
|
|
||||||
while(fragment.childNodes.length > 0){
|
while(fragment.childNodes.length > 0){
|
||||||
var child = fragment.firstChild;
|
var child = fragment.firstChild;
|
||||||
parentNode.insertBefore(child, insertBefore);
|
parentNode.insertBefore(child, insertBefore);
|
||||||
if (child.nodeType !== Node.TEXT_NODE) {
|
if (child.nodeType !== Node.TEXT_NODE) {
|
||||||
triggerEvent(child, 'load.htmx', {});
|
var newAttributes = null;
|
||||||
processNode(child);
|
if (child.id) {
|
||||||
|
var originalNode = parentNode.querySelector(child.tagName + "[id=" + child.id + "]");
|
||||||
|
if (originalNode && originalNode !== parentNode) {
|
||||||
|
newAttributes = child.cloneNode();
|
||||||
|
cloneAttributes(child, originalNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settleInfo.tasks.push(function(){
|
||||||
|
if (newAttributes) {
|
||||||
|
cloneAttributes(child, newAttributes);
|
||||||
|
}
|
||||||
|
processNode(child);
|
||||||
|
triggerEvent(child, 'load.htmx', {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -757,10 +754,6 @@ return (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processSSESource(elt, sseSrc) {
|
function processSSESource(elt, sseSrc) {
|
||||||
var detail = {
|
|
||||||
config:{withCredentials: true}
|
|
||||||
};
|
|
||||||
triggerEvent(elt, "initSSE.htmx", detail);
|
|
||||||
var source = new EventSource(sseSrc, detail.config);
|
var source = new EventSource(sseSrc, detail.config);
|
||||||
source.onerror = function (e) {
|
source.onerror = function (e) {
|
||||||
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
||||||
@ -1494,7 +1487,7 @@ return (function () {
|
|||||||
function getMetaConfig() {
|
function getMetaConfig() {
|
||||||
var element = getDocument().querySelector('meta[name="htmx-config"]');
|
var element = getDocument().querySelector('meta[name="htmx-config"]');
|
||||||
if (element) {
|
if (element) {
|
||||||
return JSON.parse(element.content);
|
return eval(element.content);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,6 @@ title: </> htmx - Attributes
|
|||||||
| [`historyCacheMissLoad.htmx`](/events#historyCacheMissLoad.htmx) | triggered on a succesful remote retrieval
|
| [`historyCacheMissLoad.htmx`](/events#historyCacheMissLoad.htmx) | triggered on a succesful remote retrieval
|
||||||
| [`historyRestore.htmx`](/events#historyRestore.htmx) | triggered when htmx handles a history restoration action
|
| [`historyRestore.htmx`](/events#historyRestore.htmx) | triggered when htmx handles a history restoration action
|
||||||
| [`beforeHistorySave.htmx`](/events#beforeHistorySave.htmx) | triggered before content is saved to the history cache
|
| [`beforeHistorySave.htmx`](/events#beforeHistorySave.htmx) | triggered before content is saved to the history cache
|
||||||
| [`initSSE.htmx`](/events#initSSE.htmx) | triggered when a new Server Sent Event source is created
|
|
||||||
| [`load.htmx`](/events#load.htmx) | triggered when new content is added to the DOM
|
| [`load.htmx`](/events#load.htmx) | triggered when new content is added to the DOM
|
||||||
| [`noSSESourceError.htmx`](/events#noSSESourceError.htmx) | triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined
|
| [`noSSESourceError.htmx`](/events#noSSESourceError.htmx) | triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined
|
||||||
| [`onLoadError.htmx`](/events#onLoadError.htmx) | triggered when an exception occurs during the onLoad handling in htmx
|
| [`onLoadError.htmx`](/events#onLoadError.htmx) | triggered when an exception occurs during the onLoad handling in htmx
|
||||||
|
@ -346,13 +346,11 @@ return (function () {
|
|||||||
var target = getDocument().getElementById(child.id);
|
var target = getDocument().getElementById(child.id);
|
||||||
if (target) {
|
if (target) {
|
||||||
var fragment;
|
var fragment;
|
||||||
if (isInlineSwap(oobValue, target)) {
|
fragment = getDocument().createDocumentFragment();
|
||||||
fragment = getDocument().createDocumentFragment();
|
fragment.appendChild(child); // pulls the child out of the existing fragment
|
||||||
fragment.appendChild(child);
|
if (!isInlineSwap(oobValue, target)) {
|
||||||
} else {
|
fragment = child; // if this is not an inline swap, we use the content of the node, not the node itself
|
||||||
fragment = child;
|
|
||||||
}
|
}
|
||||||
fragment.appendChild(child);
|
|
||||||
swap(oobValue, target, target, fragment, settleInfo);
|
swap(oobValue, target, target, fragment, settleInfo);
|
||||||
} else {
|
} else {
|
||||||
child.parentNode.removeChild(child);
|
child.parentNode.removeChild(child);
|
||||||
@ -370,27 +368,26 @@ return (function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAttributes(parentNode, fragment, settleInfo) {
|
|
||||||
forEach(fragment.querySelectorAll("[id]"), function (newNode) {
|
|
||||||
var oldNode = parentNode.querySelector(newNode.tagName + "[id=" + newNode.id + "]")
|
|
||||||
if (oldNode) {
|
|
||||||
var newAttributes = newNode.cloneNode();
|
|
||||||
cloneAttributes(newNode, oldNode);
|
|
||||||
settleInfo.tasks.push(function () {
|
|
||||||
cloneAttributes(newNode, newAttributes);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
function insertNodesBefore(parentNode, insertBefore, fragment, settleInfo) {
|
||||||
handleAttributes(parentNode, fragment, settleInfo);
|
|
||||||
while(fragment.childNodes.length > 0){
|
while(fragment.childNodes.length > 0){
|
||||||
var child = fragment.firstChild;
|
var child = fragment.firstChild;
|
||||||
parentNode.insertBefore(child, insertBefore);
|
parentNode.insertBefore(child, insertBefore);
|
||||||
if (child.nodeType !== Node.TEXT_NODE) {
|
if (child.nodeType !== Node.TEXT_NODE) {
|
||||||
triggerEvent(child, 'load.htmx', {});
|
var newAttributes = null;
|
||||||
processNode(child);
|
if (child.id) {
|
||||||
|
var originalNode = parentNode.querySelector(child.tagName + "[id=" + child.id + "]");
|
||||||
|
if (originalNode && originalNode !== parentNode) {
|
||||||
|
newAttributes = child.cloneNode();
|
||||||
|
cloneAttributes(child, originalNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settleInfo.tasks.push(function(){
|
||||||
|
if (newAttributes) {
|
||||||
|
cloneAttributes(child, newAttributes);
|
||||||
|
}
|
||||||
|
processNode(child);
|
||||||
|
triggerEvent(child, 'load.htmx', {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -757,10 +754,6 @@ return (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processSSESource(elt, sseSrc) {
|
function processSSESource(elt, sseSrc) {
|
||||||
var detail = {
|
|
||||||
config:{withCredentials: true}
|
|
||||||
};
|
|
||||||
triggerEvent(elt, "initSSE.htmx", detail);
|
|
||||||
var source = new EventSource(sseSrc, detail.config);
|
var source = new EventSource(sseSrc, detail.config);
|
||||||
source.onerror = function (e) {
|
source.onerror = function (e) {
|
||||||
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source});
|
||||||
@ -1494,7 +1487,7 @@ return (function () {
|
|||||||
function getMetaConfig() {
|
function getMetaConfig() {
|
||||||
var element = getDocument().querySelector('meta[name="htmx-config"]');
|
var element = getDocument().querySelector('meta[name="htmx-config"]');
|
||||||
if (element) {
|
if (element) {
|
||||||
return JSON.parse(element.content);
|
return eval(element.content);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -48,5 +48,28 @@ describe("hx-swap-oob attribute", function () {
|
|||||||
byId("d1").innerHTML.should.equal("Swapped");
|
byId("d1").innerHTML.should.equal("Swapped");
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('handles outerHTML response properly', function () {
|
||||||
|
this.server.respondWith("GET", "/test", "Clicked<div id='d1' foo='bar' hx-swap-oob='outerHTML'>Swapped</div>");
|
||||||
|
var div = make('<div hx-get="/test">click me</div>');
|
||||||
|
make('<div id="d1"></div>');
|
||||||
|
div.click();
|
||||||
|
this.server.respond();
|
||||||
|
byId("d1").getAttribute("foo").should.equal("bar");
|
||||||
|
div.innerHTML.should.equal("Clicked");
|
||||||
|
byId("d1").innerHTML.should.equal("Swapped");
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles innerHTML response properly', function () {
|
||||||
|
this.server.respondWith("GET", "/test", "Clicked<div id='d1' foo='bar' hx-swap-oob='innerHTML'>Swapped</div>");
|
||||||
|
var div = make('<div hx-get="/test">click me</div>');
|
||||||
|
make('<div id="d1"></div>');
|
||||||
|
div.click();
|
||||||
|
this.server.respond();
|
||||||
|
should.equal(byId("d1").getAttribute("foo"), null);
|
||||||
|
div.innerHTML.should.equal("Clicked");
|
||||||
|
byId("d1").innerHTML.should.equal("Swapped");
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ describe("hx-swap attribute", function(){
|
|||||||
swapSpec(make("<div/>")).swapStyle.should.equal("innerHTML")
|
swapSpec(make("<div/>")).swapStyle.should.equal("innerHTML")
|
||||||
swapSpec(make("<div hx-swap='innerHTML'/>")).swapStyle.should.equal("innerHTML")
|
swapSpec(make("<div hx-swap='innerHTML'/>")).swapStyle.should.equal("innerHTML")
|
||||||
swapSpec(make("<div hx-swap='innerHTML'/>")).swapDelay.should.equal(0)
|
swapSpec(make("<div hx-swap='innerHTML'/>")).swapDelay.should.equal(0)
|
||||||
swapSpec(make("<div hx-swap='innerHTML'/>")).settleDelay.should.equal(100)
|
swapSpec(make("<div hx-swap='innerHTML'/>")).settleDelay.should.equal(0) // set to 0 in tests
|
||||||
swapSpec(make("<div hx-swap='innerHTML swap:10'/>")).swapDelay.should.equal(10)
|
swapSpec(make("<div hx-swap='innerHTML swap:10'/>")).swapDelay.should.equal(10)
|
||||||
swapSpec(make("<div hx-swap='innerHTML settle:10'/>")).settleDelay.should.equal(10)
|
swapSpec(make("<div hx-swap='innerHTML settle:10'/>")).settleDelay.should.equal(10)
|
||||||
swapSpec(make("<div hx-swap='innerHTML swap:10 settle:11'/>")).swapDelay.should.equal(10)
|
swapSpec(make("<div hx-swap='innerHTML swap:10 settle:11'/>")).swapDelay.should.equal(10)
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<meta http-equiv="expires" content="0" />
|
<meta http-equiv="expires" content="0" />
|
||||||
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
|
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
|
||||||
<meta http-equiv="pragma" content="no-cache" />
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
<meta name="htmx-config" content='{"historyEnabled":false}'>
|
<meta name="htmx-config" content='{"historyEnabled":false,"defaultSettleDelay":0}'>
|
||||||
</head>
|
</head>
|
||||||
<body style="padding:20px;font-family: sans-serif">
|
<body style="padding:20px;font-family: sans-serif">
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user