From ba03597a653072dffa4da615b17777ba0ccdccfa Mon Sep 17 00:00:00 2001 From: carson Date: Mon, 25 May 2020 22:04:11 -0700 Subject: [PATCH] more release prep --- dist/htmx.js | 82 ++++++++++--------- dist/htmx.min.js | 2 +- dist/htmx.min.js.gz | Bin 6682 -> 6706 bytes www/docs.md | 3 +- www/extensions.md | 15 +++- www/js/htmx.js | 82 ++++++++++--------- www/reference.md | 10 --- www/test/0.0.4/src/htmx.js | 82 ++++++++++--------- www/test/0.0.4/test/attributes/hx-sse.js | 95 +++++++++++++++++++++++ www/test/0.0.4/test/attributes/hx-ws.js | 51 ++++++++++++ www/test/0.0.4/test/core/ajax.js | 13 ++++ www/test/0.0.4/test/index.html | 3 + 12 files changed, 313 insertions(+), 125 deletions(-) create mode 100644 www/test/0.0.4/test/attributes/hx-sse.js create mode 100644 www/test/0.0.4/test/attributes/hx-ws.js diff --git a/dist/htmx.js b/dist/htmx.js index cedcc46a..bd4bc5d8 100644 --- a/dist/htmx.js +++ b/dist/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) { + handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; parentNode.insertBefore(child, insertBefore); 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(){ - if (newAttributes) { - cloneAttributes(child, newAttributes); - } processNode(child); triggerEvent(child, 'load.htmx', {}); }); @@ -519,6 +522,8 @@ return (function () { if (trigger === "every") return {trigger: 'every', pollInterval: parseInterval(tokens[1])}; + if (trigger.indexOf("sse:") === 0) + return {trigger: 'sse', sseEvent: trigger.substr(4)}; var triggerSpec = {trigger: trigger}; for (var i = 1; i < tokens.length; i++) { @@ -662,22 +667,18 @@ return (function () { function processWebSocketInfo(elt, nodeData, info) { var values = info.split(","); for (var i = 0; i < values.length; i++) { - var value = removeWhiteSpace(values[i]); - if (value.indexOf("source:") === 0) { - processWebSocketSource(elt, value.substr(7)); + var value = splitOnWhitespace(values[i]); + if (value[0] === "connect") { + processWebSocketSource(elt, value[1]); } - if (value.indexOf("send:") === 0) { - processWebSocketSend(elt, value.substr(5)); + if (value[0] === "send") { + processWebSocketSend(elt); } } } function processWebSocketSource(elt, wssSource) { - var detail = { - protocols:[] - }; - triggerEvent(elt, "initWebSocket.htmx", detail); - var socket = new WebSocket("wss:" + wssSource, detail.protocols); + var socket = htmx.createWebSocket(wssSource); socket.onerror = function (e) { triggerErrorEvent(elt, "wsError.htmx", {error:e, socket:socket}); maybeCloseWebSocketSource(elt); @@ -712,13 +713,13 @@ return (function () { } } - function processWebSocketSend(elt, eventName) { + function processWebSocketSend(elt) { var webSocketSourceElt = getClosestMatch(elt, function (parent) { return getInternalData(parent).webSocket != null; }); if (webSocketSourceElt) { 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 rawParameters = getInputValues(elt, 'post'); var filteredParameters = filterValues(rawParameters, elt); @@ -743,18 +744,15 @@ return (function () { function processSSEInfo(elt, nodeData, info) { var values = info.split(","); for (var i = 0; i < values.length; i++) { - var value = removeWhiteSpace(values[i]); - if (value.indexOf("source:") === 0) { - processSSESource(elt, value.substr(7)); - } - if (value.indexOf("trigger:") && nodeData.verb) { - processSSETrigger(elt, nodeData.verb, nodeData.path, value.substr(8)); + var value = splitOnWhitespace(values[i]); + if (value[0] === "connect") { + processSSESource(elt, value[1]); } } } function processSSESource(elt, sseSrc) { - var source = new EventSource(sseSrc, detail.config); + var source = htmx.createEventSource(sseSrc); source.onerror = function (e) { triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source}); maybeCloseSSESource(elt); @@ -769,7 +767,7 @@ return (function () { if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { - if (!maybeCloseSSESource(sseEventSource)) { + if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { issueAjaxRequest(elt, verb, path); } else { @@ -807,7 +805,9 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.trigger === "revealed") { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, verb, path, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { initScrollHandler(); maybeReveal(elt); } else if (triggerSpec.trigger === "load") { @@ -835,13 +835,15 @@ return (function () { if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { boostElement(elt, nodeData, triggerSpecs); } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); } - var sseInfo = getAttributeValue(elt, 'hx-ws'); - if (sseInfo) { - processWebSocketInfo(elt, nodeData, sseInfo); + + var wsInfo = getAttributeValue(elt, 'hx-ws'); + if (wsInfo) { + processWebSocketInfo(elt, nodeData, wsInfo); } triggerEvent(elt, "processedNode.htmx"); } @@ -1487,7 +1489,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { - return eval(element.content); + return JSON.parse(element.content); } else { return null; } @@ -1539,7 +1541,13 @@ return (function () { includeIndicatorStyles:true }, parseInterval:parseInterval, - _:internalEval + _:internalEval, + createEventSource: function(url){ + return new EventSource(url, {withCredentials:true}) + }, + createWebSocket: function(url){ + return new WebSocket(url, []); + } } } )() diff --git a/dist/htmx.min.js b/dist/htmx.min.js index cb7348cb..67c58ed8 100644 --- a/dist/htmx.min.js +++ b/dist/htmx.min.js @@ -1 +1 @@ -(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var t=["get","post","put","delete","patch"];function a(e){if(e==="null"||e==="false"||e===""){return null}else if(e.lastIndexOf("ms")===e.length-2){return parseFloat(e.substr(0,e.length-2))}else if(e.lastIndexOf("s")===e.length-1){return parseFloat(e.substr(0,e.length-1))*1e3}else{return parseFloat(e)}}function u(e,t){return e.getAttribute&&e.getAttribute(t)}function w(e,t){return u(e,t)||u(e,"data-"+t)}function o(e){return e.parentElement}function E(){return document}function l(e,t){if(t(e)){return e}else if(o(e)){return l(o(e),t)}else{return null}}function O(e,t){var r=null;l(e,function(e){return r=w(e,t)});return r}function f(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function r(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function n(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=E().createDocumentFragment()}return i}function s(e){var t=r(e);switch(t){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return n(""+e+"
",1);case"col":return n(""+e+"
",2);case"tr":return n(""+e+"
",2);case"td":case"th":return n(""+e+"
",3);default:return n(e,0)}}function i(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function c(e){return i(e,"Function")}function v(e){return i(e,"Object")}function L(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function h(e){var t=[];if(e){for(var r=0;r=0}function m(e){return E().body.contains(e)}function g(e){return e.split(/\s+/)}function p(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function e(e){return eval(e)}function x(t){var e=htmx.on("load.htmx",function(e){t(e.detail.elt)});return e}function y(){htmx.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function b(e,t){if(t){return e.querySelector(t)}else{return E().body.querySelector(e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return E().body.querySelectorAll(e)}}function T(e,t){if(t){setTimeout(function(){T(e)},t)}else{e.parentElement.removeChild(e)}}function H(e,t,r){if(r){setTimeout(function(){H(e,t)},r)}else{e.classList.add(t)}}function q(e,t,r){if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.remove(t)}}function N(e,t){e.classList.toggle(t)}function X(e,t){C(e.parentElement.children,function(e){q(e,t)});H(e,t)}function A(e,t){do{if(e==null||f(e,t))return e}while(e=e&&o(e))}function R(e,t,r){if(c(t)){return{target:E().body,event:e,listener:t}}else{return{target:e,event:t,listener:r}}}function k(t,r,n){et(function(){var e=R(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=c(r);return e?r:n}function D(t,r,n){et(function(){var e=R(t,r,n);e.target.removeEventListener(e.event,e.listener)});return c(r)?r:n}function M(e){var t=l(e,function(e){return w(e,"hx-target")!==null});if(t){var r=w(t,"hx-target");if(r==="this"){return t}else if(r.indexOf("closest ")===0){return A(e,r.substr(8))}else{return E().querySelector(r)}}else{var n=L(e);if(n.boosted){return E().body}else{return e}}}function I(t,r){C(t.attributes,function(e){if(!r.hasAttribute(e.name)){t.removeAttribute(e.name)}});C(r.attributes,function(e){t.setAttribute(e.name,e.value)})}function F(e,t){var r=$e(t);for(var n=0;n0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE){var o=null;if(i.id){var a=e.querySelector(i.tagName+"[id="+i.id+"]");if(a&&a!==e){o=i.cloneNode();I(i,a)}}n.tasks.push(function(){if(o){I(i,o)}xe(i);Ee(i,"load.htmx",{})})}}}function U(e,t,r){if(e.tagName==="BODY"){return G(e,t)}else{var n=e.previousSibling;J(o(e),e,t,r);if(n==null){var i=o(e).firstChild}else{var i=n.nextSibling}while(i&&i!=e){r.elts.push(i);i=i.nextSibling}o(e).removeChild(e)}}function W(e,t,r){return J(e,e.firstChild,t,r)}function z(e,t,r){return J(o(e),e,t,r)}function B(e,t,r){return J(e,null,t,r)}function V(e,t,r){return J(o(e),e.nextSibling,t,r)}function G(e,t,r){var n=e.firstChild;J(e,n,t,r);if(n){while(n.nextSibling){e.removeChild(n.nextSibling)}e.removeChild(n)}}function Y(e,t){var r=O(e,"hx-select");if(r){var n=E().createDocumentFragment();C(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function _(e,t,r,n,i){switch(e){case"outerHTML":U(r,n,i);return;case"afterbegin":W(r,n,i);return;case"beforebegin":z(r,n,i);return;case"beforeend":B(r,n,i);return;case"afterend":V(r,n,i);return;default:var o=$e(t);for(var a=0;ahtmx.config.historyCacheSize){i.shift()}localStorage.setItem("htmx-history-cache",JSON.stringify(i))}function Te(e){var t=JSON.parse(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r=200&&this.status<400){Ee(E().body,"historyCacheMissLoad.htmx",i);var e=s(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Le();var r=Ge(t);G(t,e,r);Ne(r.tasks);Oe=n}else{Se(E().body,"historyCacheMissLoadError.htmx",i)}};e.send()}function Ae(e){He(Oe);e=e||location.pathname+location.search;Ee(E().body,"historyRestore.htmx",{path:e});var t=Te(e);if(t){var r=s(t.content);var n=Le();var i=Ge(n);G(n,r,i);Ne(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);Oe=e}else{Xe(e)}}function Re(e){return O(e,"hx-push-url")==="true"||e.tagName==="A"&&L(e).boosted}function ke(e){Me(e,"add")}function De(e){Me(e,"remove")}function Me(e,t){var r=O(e,"hx-indicator");if(r){var n=E().querySelectorAll(r)}else{n=[e]}C(n,function(e){e.classList[t].call(e.classList,"htmx-request")})}function Ie(e,t){for(var r=0;r0){r["swapStyle"]=n[0];for(var i=1;i=200&&this.status<400){if(this.status===286){$(a)}if(this.status!==204){if(!Ee(a,"beforeSwap.htmx",S))return;var i=this.response;C($e(a),function(e){i=e.transformResponse(i,s,a)});if(n){He()}var o=Be(a);l.classList.add("htmx-swapping");var e=function(){try{var e=Ge(l);K(o.swapStyle,l,a,i,e);l.classList.remove("htmx-swapping");C(e.elts,function(e){if(e.classList){e.classList.add("htmx-settling")}});Ee(a,"afterSwap.htmx",S);if(p){location.hash=p}var t=function(){C(e.tasks,function(e){e.call()});C(e.elts,function(e){if(e.classList){e.classList.remove("htmx-settling")}});if(n){qe(r||u)}Ee(a,"afterSettle.htmx",S)};if(o.settleDelay>0){setTimeout(t,o.settleDelay)}else{t()}}catch(e){Se(a,"swapError.htmx",S);throw e}};if(o.swapDelay>0){setTimeout(e,o.swapDelay)}else{e()}}}else{Se(a,"responseError.htmx",S)}}catch(e){S["exception"]=e;Se(a,"onLoadError.htmx",S);throw e}finally{De(a);Ee(a,"afterRequest.htmx",S);Ee(a,"afterOnLoad.htmx",S);f()}};s.onerror=function(){De(a);Se(a,"afterRequest.htmx",S);Se(a,"sendError.htmx",S);f()};if(!Ee(a,"beforeRequest.htmx",S))return f();ke(a);s.send(e==="get"?null:Ve(s,a,h))}var _e={};function Ke(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Qe(e,t){_e[e]=p(Ke(),t)}function Ze(e){delete _e[e]}function $e(e,r){if(e==null){return r}if(r==null){r=[]}var t=w(e,"hx-ext");if(t){C(t.split(","),function(e){e=e.replace(/ /g,"");var t=_e[e];if(t&&r.indexOf(t)<0){r.push(t)}})}return $e(o(e),r)}function et(e){if(E().readyState!=="loading"){e()}else{E().addEventListener("DOMContentLoaded",e)}}(function(){var e=tt();if(e===null||e.includeIndicatorStyles!==false){E().head.insertAdjacentHTML("beforeend","")}})();function tt(){var e=E().querySelector('meta[name="htmx-config"]');if(e){return eval(e.content)}else{return null}}function rt(){var e=tt();if(e){htmx.config=p(htmx.config,e)}}et(function(){rt();var e=E().body;xe(e);Ee(e,"load.htmx",{});window.onpopstate=function(){Ae()}});return{onLoad:x,process:xe,on:k,off:D,trigger:Ee,find:b,findAll:S,closest:A,remove:T,addClass:H,removeClass:q,toggleClass:N,takeClass:X,defineExtension:Qe,removeExtension:Ze,logAll:y,logger:null,config:{historyEnabled:true,historyCacheSize:10,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:100,includeIndicatorStyles:true},parseInterval:a,_:e}}()}); \ No newline at end of file +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else{e.htmx=t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var t=["get","post","put","delete","patch"];function a(e){if(e==="null"||e==="false"||e===""){return null}else if(e.lastIndexOf("ms")===e.length-2){return parseFloat(e.substr(0,e.length-2))}else if(e.lastIndexOf("s")===e.length-1){return parseFloat(e.substr(0,e.length-1))*1e3}else{return parseFloat(e)}}function u(e,t){return e.getAttribute&&e.getAttribute(t)}function w(e,t){return u(e,t)||u(e,"data-"+t)}function o(e){return e.parentElement}function E(){return document}function l(e,t){if(t(e)){return e}else if(o(e)){return l(o(e),t)}else{return null}}function L(e,t){var r=null;l(e,function(e){return r=w(e,t)});return r}function s(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function r(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function n(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=E().createDocumentFragment()}return i}function f(e){var t=r(e);switch(t){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return n(""+e+"
",1);case"col":return n(""+e+"
",2);case"tr":return n(""+e+"
",2);case"td":case"th":return n(""+e+"
",3);default:return n(e,0)}}function i(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function c(e){return i(e,"Function")}function v(e){return i(e,"Object")}function O(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function h(e){var t=[];if(e){for(var r=0;r=0}function m(e){return E().body.contains(e)}function g(e){return e.split(/\s+/)}function p(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function e(e){return eval(e)}function x(t){var e=htmx.on("load.htmx",function(e){t(e.detail.elt)});return e}function y(){htmx.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function b(e,t){if(t){return e.querySelector(t)}else{return E().body.querySelector(e)}}function S(e,t){if(t){return e.querySelectorAll(t)}else{return E().body.querySelectorAll(e)}}function T(e,t){if(t){setTimeout(function(){T(e)},t)}else{e.parentElement.removeChild(e)}}function H(e,t,r){if(r){setTimeout(function(){H(e,t)},r)}else{e.classList.add(t)}}function q(e,t,r){if(r){setTimeout(function(){q(e,t)},r)}else{e.classList.remove(t)}}function N(e,t){e.classList.toggle(t)}function X(e,t){C(e.parentElement.children,function(e){q(e,t)});H(e,t)}function A(e,t){do{if(e==null||s(e,t))return e}while(e=e&&o(e))}function k(e,t,r){if(c(t)){return{target:E().body,event:e,listener:t}}else{return{target:e,event:t,listener:r}}}function R(t,r,n){tt(function(){var e=k(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=c(r);return e?r:n}function D(t,r,n){tt(function(){var e=k(t,r,n);e.target.removeEventListener(e.event,e.listener)});return c(r)?r:n}function M(e){var t=l(e,function(e){return w(e,"hx-target")!==null});if(t){var r=w(t,"hx-target");if(r==="this"){return t}else if(r.indexOf("closest ")===0){return A(e,r.substr(8))}else{return E().querySelector(r)}}else{var n=O(e);if(n.boosted){return E().body}else{return e}}}function I(t,r){C(t.attributes,function(e){if(!r.hasAttribute(e.name)){t.removeAttribute(e.name)}});C(r.attributes,function(e){t.setAttribute(e.name,e.value)})}function F(e,t){var r=et(t);for(var n=0;n0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE){n.tasks.push(function(){ye(i);Le(i,"load.htmx",{})})}}}function z(e,t,r){if(e.tagName==="BODY"){return Y(e,t)}else{var n=e.previousSibling;U(o(e),e,t,r);if(n==null){var i=o(e).firstChild}else{var i=n.nextSibling}while(i&&i!=e){r.elts.push(i);i=i.nextSibling}o(e).removeChild(e)}}function B(e,t,r){return U(e,e.firstChild,t,r)}function W(e,t,r){return U(o(e),e,t,r)}function V(e,t,r){return U(e,null,t,r)}function G(e,t,r){return U(o(e),e.nextSibling,t,r)}function Y(e,t,r){var n=e.firstChild;U(e,n,t,r);if(n){while(n.nextSibling){e.removeChild(n.nextSibling)}e.removeChild(n)}}function _(e,t){var r=L(e,"hx-select");if(r){var n=E().createDocumentFragment();C(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function K(e,t,r,n,i){switch(e){case"outerHTML":z(r,n,i);return;case"afterbegin":B(r,n,i);return;case"beforebegin":W(r,n,i);return;case"beforeend":V(r,n,i);return;case"afterend":G(r,n,i);return;default:var o=et(t);for(var a=0;ahtmx.config.historyCacheSize){i.shift()}localStorage.setItem("htmx-history-cache",JSON.stringify(i))}function He(e){var t=JSON.parse(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r=200&&this.status<400){Le(E().body,"historyCacheMissLoad.htmx",i);var e=f(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=Ce();var r=Ye(t);Y(t,e,r);Xe(r.tasks);Oe=n}else{we(E().body,"historyCacheMissLoadError.htmx",i)}};e.send()}function ke(e){qe(Oe);e=e||location.pathname+location.search;Le(E().body,"historyRestore.htmx",{path:e});var t=He(e);if(t){var r=f(t.content);var n=Ce();var i=Ye(n);Y(n,r,i);Xe(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);Oe=e}else{Ae(e)}}function Re(e){return L(e,"hx-push-url")==="true"||e.tagName==="A"&&O(e).boosted}function De(e){Ie(e,"add")}function Me(e){Ie(e,"remove")}function Ie(e,t){var r=L(e,"hx-indicator");if(r){var n=E().querySelectorAll(r)}else{n=[e]}C(n,function(e){e.classList[t].call(e.classList,"htmx-request")})}function Fe(e,t){for(var r=0;r0){r["swapStyle"]=n[0];for(var i=1;i=200&&this.status<400){if(this.status===286){ee(a)}if(this.status!==204){if(!Le(a,"beforeSwap.htmx",S))return;var i=this.response;C(et(a),function(e){i=e.transformResponse(i,f,a)});if(n){qe()}var o=Ve(a);l.classList.add("htmx-swapping");var e=function(){try{var e=Ye(l);Q(o.swapStyle,l,a,i,e);l.classList.remove("htmx-swapping");C(e.elts,function(e){if(e.classList){e.classList.add("htmx-settling")}});Le(a,"afterSwap.htmx",S);if(p){location.hash=p}var t=function(){C(e.tasks,function(e){e.call()});C(e.elts,function(e){if(e.classList){e.classList.remove("htmx-settling")}});if(n){Ne(r||u)}Le(a,"afterSettle.htmx",S)};if(o.settleDelay>0){setTimeout(t,o.settleDelay)}else{t()}}catch(e){we(a,"swapError.htmx",S);throw e}};if(o.swapDelay>0){setTimeout(e,o.swapDelay)}else{e()}}}else{we(a,"responseError.htmx",S)}}catch(e){S["exception"]=e;we(a,"onLoadError.htmx",S);throw e}finally{Me(a);Le(a,"afterRequest.htmx",S);Le(a,"afterOnLoad.htmx",S);s()}};f.onerror=function(){Me(a);we(a,"afterRequest.htmx",S);we(a,"sendError.htmx",S);s()};if(!Le(a,"beforeRequest.htmx",S))return s();De(a);f.send(e==="get"?null:Ge(f,a,h))}var Ke={};function Qe(){return{onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function Ze(e,t){Ke[e]=p(Qe(),t)}function $e(e){delete Ke[e]}function et(e,r){if(e==null){return r}if(r==null){r=[]}var t=w(e,"hx-ext");if(t){C(t.split(","),function(e){e=e.replace(/ /g,"");var t=Ke[e];if(t&&r.indexOf(t)<0){r.push(t)}})}return et(o(e),r)}function tt(e){if(E().readyState!=="loading"){e()}else{E().addEventListener("DOMContentLoaded",e)}}(function(){var e=rt();if(e===null||e.includeIndicatorStyles!==false){E().head.insertAdjacentHTML("beforeend","")}})();function rt(){var e=E().querySelector('meta[name="htmx-config"]');if(e){return JSON.parse(e.content)}else{return null}}function nt(){var e=rt();if(e){htmx.config=p(htmx.config,e)}}tt(function(){nt();var e=E().body;ye(e);Le(e,"load.htmx",{});window.onpopstate=function(){ke()}});return{onLoad:x,process:ye,on:R,off:D,trigger:Le,find:b,findAll:S,closest:A,remove:T,addClass:H,removeClass:q,toggleClass:N,takeClass:X,defineExtension:Ze,removeExtension:$e,logAll:y,logger:null,config:{historyEnabled:true,historyCacheSize:10,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:100,includeIndicatorStyles:true},parseInterval:a,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){return new WebSocket(e,[])}}}()}); \ No newline at end of file diff --git a/dist/htmx.min.js.gz b/dist/htmx.min.js.gz index 90508e44c445436d93e76c583d0d7c95d4a6e2e8..c7146f213e5a9516991cbbcd25bcc4e0a2e0cf9e 100644 GIT binary patch literal 6706 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 IvC&Ha0B!yGTmS$7 literal 6682 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 diff --git a/www/docs.md b/www/docs.md index c814489c..e989a8c5 100644 --- a/www/docs.md +++ b/www/docs.md @@ -523,11 +523,10 @@ Htmx offers some officially supported extensions that are tested against the htm | [`json-enc`](/extensions/json-enc) | use JSON encoding in the body of requests, rather than the default `x-www-form-urlencoded` | [`morphdom-swap`](/extensions/morphdom-swap) | an extension for using the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the swapping mechanism in htmx. | [`client-side-templates`](/extensions/client-side-templates) | support for client side template processing of JSON responses -| [`debug`](/extensions/debug) | an extension for debugging of a particular element using htmx | [`path-deps`](/extensions/path-deps) | an extension for expressing path-based dependencies [similar to intercoolerjs](http://intercoolerjs.org/docs.html#dependencies) | [`class-tools`](/extensions/class-tools) | an extension for manipulating timed addition and removal of classes on HTML elements -See the [references page](/reference#extensions) for a complete list. +See the [Extensions](/extensions#list) for a complete list. ## [Events & Logging](#events) diff --git a/www/extensions.md b/www/extensions.md index 30eb0173..b3ab7177 100644 --- a/www/extensions.md +++ b/www/extensions.md @@ -46,4 +46,17 @@ would say: ``` Note that the `hx-ext` tag may be placed on parent elements if you want a plugin to apply to an entire swath of the dom, -and on the `body` tag for it to apply to all htmx requests. \ No newline at end of file +and on the `body` tag for it to apply to all htmx requests. + +## [Extensions Reference](#list) + +The following extensions that are tested and distributed with htmx: + +| Extension | Description +|-----------|------------- +| [`json-enc`](/extensions/json-enc) | use JSON encoding in the body of requests, rather than the default `x-www-form-urlencoded` +| [`morphdom-swap`](/extensions/morphdom-swap) | an extension for using the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the swapping mechanism in htmx. +| [`client-side-templates`](/extensions/client-side-templates) | support for client side template processing of JSON responses +| [`debug`](/extensions/debug) | an extension for debugging of a particular element using htmx +| [`path-deps`](/extensions/path-deps) | an extension for expressing path-based dependencies [similar to intercoolerjs](http://intercoolerjs.org/docs.html#dependencies) +| [`class-tools`](/extensions/class-tools) | an extension for manipulating timed addition and removal of classes on HTML elements diff --git a/www/js/htmx.js b/www/js/htmx.js index cedcc46a..bd4bc5d8 100644 --- a/www/js/htmx.js +++ b/www/js/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) { + handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; parentNode.insertBefore(child, insertBefore); 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(){ - if (newAttributes) { - cloneAttributes(child, newAttributes); - } processNode(child); triggerEvent(child, 'load.htmx', {}); }); @@ -519,6 +522,8 @@ return (function () { if (trigger === "every") return {trigger: 'every', pollInterval: parseInterval(tokens[1])}; + if (trigger.indexOf("sse:") === 0) + return {trigger: 'sse', sseEvent: trigger.substr(4)}; var triggerSpec = {trigger: trigger}; for (var i = 1; i < tokens.length; i++) { @@ -662,22 +667,18 @@ return (function () { function processWebSocketInfo(elt, nodeData, info) { var values = info.split(","); for (var i = 0; i < values.length; i++) { - var value = removeWhiteSpace(values[i]); - if (value.indexOf("source:") === 0) { - processWebSocketSource(elt, value.substr(7)); + var value = splitOnWhitespace(values[i]); + if (value[0] === "connect") { + processWebSocketSource(elt, value[1]); } - if (value.indexOf("send:") === 0) { - processWebSocketSend(elt, value.substr(5)); + if (value[0] === "send") { + processWebSocketSend(elt); } } } function processWebSocketSource(elt, wssSource) { - var detail = { - protocols:[] - }; - triggerEvent(elt, "initWebSocket.htmx", detail); - var socket = new WebSocket("wss:" + wssSource, detail.protocols); + var socket = htmx.createWebSocket(wssSource); socket.onerror = function (e) { triggerErrorEvent(elt, "wsError.htmx", {error:e, socket:socket}); maybeCloseWebSocketSource(elt); @@ -712,13 +713,13 @@ return (function () { } } - function processWebSocketSend(elt, eventName) { + function processWebSocketSend(elt) { var webSocketSourceElt = getClosestMatch(elt, function (parent) { return getInternalData(parent).webSocket != null; }); if (webSocketSourceElt) { 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 rawParameters = getInputValues(elt, 'post'); var filteredParameters = filterValues(rawParameters, elt); @@ -743,18 +744,15 @@ return (function () { function processSSEInfo(elt, nodeData, info) { var values = info.split(","); for (var i = 0; i < values.length; i++) { - var value = removeWhiteSpace(values[i]); - if (value.indexOf("source:") === 0) { - processSSESource(elt, value.substr(7)); - } - if (value.indexOf("trigger:") && nodeData.verb) { - processSSETrigger(elt, nodeData.verb, nodeData.path, value.substr(8)); + var value = splitOnWhitespace(values[i]); + if (value[0] === "connect") { + processSSESource(elt, value[1]); } } } function processSSESource(elt, sseSrc) { - var source = new EventSource(sseSrc, detail.config); + var source = htmx.createEventSource(sseSrc); source.onerror = function (e) { triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source}); maybeCloseSSESource(elt); @@ -769,7 +767,7 @@ return (function () { if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { - if (!maybeCloseSSESource(sseEventSource)) { + if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { issueAjaxRequest(elt, verb, path); } else { @@ -807,7 +805,9 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.trigger === "revealed") { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, verb, path, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { initScrollHandler(); maybeReveal(elt); } else if (triggerSpec.trigger === "load") { @@ -835,13 +835,15 @@ return (function () { if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { boostElement(elt, nodeData, triggerSpecs); } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); } - var sseInfo = getAttributeValue(elt, 'hx-ws'); - if (sseInfo) { - processWebSocketInfo(elt, nodeData, sseInfo); + + var wsInfo = getAttributeValue(elt, 'hx-ws'); + if (wsInfo) { + processWebSocketInfo(elt, nodeData, wsInfo); } triggerEvent(elt, "processedNode.htmx"); } @@ -1487,7 +1489,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { - return eval(element.content); + return JSON.parse(element.content); } else { return null; } @@ -1539,7 +1541,13 @@ return (function () { includeIndicatorStyles:true }, parseInterval:parseInterval, - _:internalEval + _:internalEval, + createEventSource: function(url){ + return new EventSource(url, {withCredentials:true}) + }, + createWebSocket: function(url){ + return new WebSocket(url, []); + } } } )() diff --git a/www/reference.md b/www/reference.md index 6aa65b52..ef28e987 100644 --- a/www/reference.md +++ b/www/reference.md @@ -93,13 +93,3 @@ title: htmx - Attributes | [`swapError.htmx`](/events#swapError.htmx) | triggered when an error occurs during the swap phase | [`targetError.htmx`](/events#targetError.htmx) | triggered when an invalid target is specified -## [Extensions Reference](#extensions) - -| Extension | Description -|-----------|------------- -| [`json-enc`](/extensions/json-enc) | use JSON encoding in the body of requests, rather than the default `x-www-form-urlencoded` -| [`morphdom-swap`](/extensions/morphdom-swap) | an extension for using the [morphdom](https://github.com/patrick-steele-idem/morphdom) library as the swapping mechanism in htmx. -| [`client-side-templates`](/extensions/client-side-templates) | support for client side template processing of JSON responses -| [`debug`](/extensions/debug) | an extension for debugging of a particular element using htmx -| [`path-deps`](/extensions/path-deps) | an extension for expressing path-based dependencies [similar to intercoolerjs](http://intercoolerjs.org/docs.html#dependencies) -| [`class-tools`](/extensions/class-tools) | an extension for manipulating timed addition and removal of classes on HTML elements diff --git a/www/test/0.0.4/src/htmx.js b/www/test/0.0.4/src/htmx.js index cedcc46a..bd4bc5d8 100644 --- a/www/test/0.0.4/src/htmx.js +++ b/www/test/0.0.4/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) { + handleAttributes(parentNode, fragment, settleInfo); while(fragment.childNodes.length > 0){ var child = fragment.firstChild; parentNode.insertBefore(child, insertBefore); 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(){ - if (newAttributes) { - cloneAttributes(child, newAttributes); - } processNode(child); triggerEvent(child, 'load.htmx', {}); }); @@ -519,6 +522,8 @@ return (function () { if (trigger === "every") return {trigger: 'every', pollInterval: parseInterval(tokens[1])}; + if (trigger.indexOf("sse:") === 0) + return {trigger: 'sse', sseEvent: trigger.substr(4)}; var triggerSpec = {trigger: trigger}; for (var i = 1; i < tokens.length; i++) { @@ -662,22 +667,18 @@ return (function () { function processWebSocketInfo(elt, nodeData, info) { var values = info.split(","); for (var i = 0; i < values.length; i++) { - var value = removeWhiteSpace(values[i]); - if (value.indexOf("source:") === 0) { - processWebSocketSource(elt, value.substr(7)); + var value = splitOnWhitespace(values[i]); + if (value[0] === "connect") { + processWebSocketSource(elt, value[1]); } - if (value.indexOf("send:") === 0) { - processWebSocketSend(elt, value.substr(5)); + if (value[0] === "send") { + processWebSocketSend(elt); } } } function processWebSocketSource(elt, wssSource) { - var detail = { - protocols:[] - }; - triggerEvent(elt, "initWebSocket.htmx", detail); - var socket = new WebSocket("wss:" + wssSource, detail.protocols); + var socket = htmx.createWebSocket(wssSource); socket.onerror = function (e) { triggerErrorEvent(elt, "wsError.htmx", {error:e, socket:socket}); maybeCloseWebSocketSource(elt); @@ -712,13 +713,13 @@ return (function () { } } - function processWebSocketSend(elt, eventName) { + function processWebSocketSend(elt) { var webSocketSourceElt = getClosestMatch(elt, function (parent) { return getInternalData(parent).webSocket != null; }); if (webSocketSourceElt) { 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 rawParameters = getInputValues(elt, 'post'); var filteredParameters = filterValues(rawParameters, elt); @@ -743,18 +744,15 @@ return (function () { function processSSEInfo(elt, nodeData, info) { var values = info.split(","); for (var i = 0; i < values.length; i++) { - var value = removeWhiteSpace(values[i]); - if (value.indexOf("source:") === 0) { - processSSESource(elt, value.substr(7)); - } - if (value.indexOf("trigger:") && nodeData.verb) { - processSSETrigger(elt, nodeData.verb, nodeData.path, value.substr(8)); + var value = splitOnWhitespace(values[i]); + if (value[0] === "connect") { + processSSESource(elt, value[1]); } } } function processSSESource(elt, sseSrc) { - var source = new EventSource(sseSrc, detail.config); + var source = htmx.createEventSource(sseSrc); source.onerror = function (e) { triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source}); maybeCloseSSESource(elt); @@ -769,7 +767,7 @@ return (function () { if (sseSourceElt) { var sseEventSource = getInternalData(sseSourceElt).sseEventSource; var sseListener = function () { - if (!maybeCloseSSESource(sseEventSource)) { + if (!maybeCloseSSESource(sseSourceElt)) { if (bodyContains(elt)) { issueAjaxRequest(elt, verb, path); } else { @@ -807,7 +805,9 @@ return (function () { nodeData.path = path; nodeData.verb = verb; triggerSpecs.forEach(function(triggerSpec) { - if (triggerSpec.trigger === "revealed") { + if (triggerSpec.sseEvent) { + processSSETrigger(elt, verb, path, triggerSpec.sseEvent); + } else if (triggerSpec.trigger === "revealed") { initScrollHandler(); maybeReveal(elt); } else if (triggerSpec.trigger === "load") { @@ -835,13 +835,15 @@ return (function () { if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { boostElement(elt, nodeData, triggerSpecs); } + var sseInfo = getAttributeValue(elt, 'hx-sse'); if (sseInfo) { processSSEInfo(elt, nodeData, sseInfo); } - var sseInfo = getAttributeValue(elt, 'hx-ws'); - if (sseInfo) { - processWebSocketInfo(elt, nodeData, sseInfo); + + var wsInfo = getAttributeValue(elt, 'hx-ws'); + if (wsInfo) { + processWebSocketInfo(elt, nodeData, wsInfo); } triggerEvent(elt, "processedNode.htmx"); } @@ -1487,7 +1489,7 @@ return (function () { function getMetaConfig() { var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { - return eval(element.content); + return JSON.parse(element.content); } else { return null; } @@ -1539,7 +1541,13 @@ return (function () { includeIndicatorStyles:true }, parseInterval:parseInterval, - _:internalEval + _:internalEval, + createEventSource: function(url){ + return new EventSource(url, {withCredentials:true}) + }, + createWebSocket: function(url){ + return new WebSocket(url, []); + } } } )() diff --git a/www/test/0.0.4/test/attributes/hx-sse.js b/www/test/0.0.4/test/attributes/hx-sse.js new file mode 100644 index 00000000..2efce22b --- /dev/null +++ b/www/test/0.0.4/test/attributes/hx-sse.js @@ -0,0 +1,95 @@ +describe("hx-sse attribute", function() { + + function mockEventSource() { + var listeners = {}; + var mockEventSource = { + addEventListener : function(message, l) { + listeners[message] = l; + }, + sendEvent : function(event) { + var listener = listeners[event]; + if(listener){ + listener(); + } + }, + }; + return mockEventSource; + } + + beforeEach(function () { + this.server = makeServer(); + var eventSource = mockEventSource(); + this.eventSource = eventSource; + clearWorkArea(); + htmx.createEventSource = function(){ return eventSource }; + }); + afterEach(function () { + this.server.restore(); + clearWorkArea(); + }); + + it('handles basic sse triggering', function () { + + this.server.respondWith("GET", "/d1", "div1 updated"); + this.server.respondWith("GET", "/d2", "div2 updated"); + + var div = make('
' + + '
div1
' + + '
div2
' + + '
'); + + this.eventSource.sendEvent("e1"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1 updated"); + byId("d2").innerHTML.should.equal("div2"); + + this.eventSource.sendEvent("e2"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1 updated"); + byId("d2").innerHTML.should.equal("div2 updated"); + }) + + it('does not trigger events that arent named', function () { + + this.server.respondWith("GET", "/d1", "div1 updated"); + + var div = make('
' + + '
div1
' + + '
'); + + this.eventSource.sendEvent("foo"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e2"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e1"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1 updated"); + }) + + it('does not trigger events not on decendents', function () { + + this.server.respondWith("GET", "/d1", "div1 updated"); + + var div = make('
' + + '
div1
'); + + this.eventSource.sendEvent("foo"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e2"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + + this.eventSource.sendEvent("e1"); + this.server.respond(); + byId("d1").innerHTML.should.equal("div1"); + }) + + +}); + diff --git a/www/test/0.0.4/test/attributes/hx-ws.js b/www/test/0.0.4/test/attributes/hx-ws.js new file mode 100644 index 00000000..ad1cb6a5 --- /dev/null +++ b/www/test/0.0.4/test/attributes/hx-ws.js @@ -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('
div1
div2
'); + this.socket.write("
replaced
") + byId("d1").innerHTML.should.equal("replaced"); + byId("d2").innerHTML.should.equal("div2"); + }) + + it('handles a basic send', function () { + var div = make('
div1
'); + byId("d1").click(); + var lastSent = this.socket.getLastSent(); + var data = JSON.parse(lastSent); + data.HEADERS["X-HX-Request"].should.equal("true"); + }) + +}); + diff --git a/www/test/0.0.4/test/core/ajax.js b/www/test/0.0.4/test/core/ajax.js index 4f5bc1fd..eb56ebbb 100644 --- a/www/test/0.0.4/test/core/ajax.js +++ b/www/test/0.0.4/test/core/ajax.js @@ -305,6 +305,19 @@ describe("Core htmx AJAX Tests", function(){ div.innerHTML.should.equal("
foo
"); }); + it('properly settles attributes on interior elements', function(done) + { + this.server.respondWith("GET", "/test", "
"); + var div = make("
"); + 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() { var values; diff --git a/www/test/0.0.4/test/index.html b/www/test/0.0.4/test/index.html index ae78f4e9..8af64347 100644 --- a/www/test/0.0.4/test/index.html +++ b/www/test/0.0.4/test/index.html @@ -74,10 +74,13 @@ + + +