diff options
-rw-r--r-- | README.md | 16 | ||||
-rw-r--r-- | TODO.md | 12 | ||||
-rw-r--r-- | dist/htmx.js (renamed from dist/kutty.js) | 46 | ||||
-rw-r--r-- | dist/htmx.min.js (renamed from dist/kutty.min.js) | 2 | ||||
-rw-r--r-- | dist/htmx.min.js.gz (renamed from dist/kutty.min.js.gz) | bin | 5729 -> 5729 bytes | |||
-rw-r--r-- | package-lock.json | 2 | ||||
-rw-r--r-- | package.json | 18 | ||||
-rw-r--r-- | scripts/www.js | 2 | ||||
-rw-r--r-- | src/htmx.js (renamed from src/kutty.js) | 168 | ||||
-rw-r--r-- | test/attributes/hx-boost.js (renamed from test/attributes/kt-boost.js) | 10 | ||||
-rw-r--r-- | test/attributes/hx-classes.js (renamed from test/attributes/kt-classes.js) | 6 | ||||
-rw-r--r-- | test/attributes/hx-delete.js (renamed from test/attributes/kt-delete.js) | 4 | ||||
-rw-r--r-- | test/attributes/hx-error-url.js (renamed from test/attributes/kt-error-url.js) | 4 | ||||
-rw-r--r-- | test/attributes/hx-get.js (renamed from test/attributes/kt-get.js) | 6 | ||||
-rw-r--r-- | test/attributes/hx-include.js (renamed from test/attributes/kt-include.js) | 24 | ||||
-rw-r--r-- | test/attributes/hx-indicator.js (renamed from test/attributes/kt-indicator.js) | 22 | ||||
-rw-r--r-- | test/attributes/hx-params.js (renamed from test/attributes/kt-params.js) | 10 | ||||
-rw-r--r-- | test/attributes/hx-patch.js (renamed from test/attributes/kt-patch.js) | 4 | ||||
-rw-r--r-- | test/attributes/hx-post.js (renamed from test/attributes/kt-post.js) | 4 | ||||
-rw-r--r-- | test/attributes/hx-push-url.js (renamed from test/attributes/kt-push-url.js) | 26 | ||||
-rw-r--r-- | test/attributes/hx-put.js (renamed from test/attributes/kt-put.js) | 4 | ||||
-rw-r--r-- | test/attributes/hx-select.js (renamed from test/attributes/kt-select.js) | 6 | ||||
-rw-r--r-- | test/attributes/hx-swap-oob.js (renamed from test/attributes/kt-swap-oob.js) | 14 | ||||
-rw-r--r-- | test/attributes/hx-swap.js (renamed from test/attributes/kt-swap.js) | 66 | ||||
-rw-r--r-- | test/attributes/hx-target.js (renamed from test/attributes/kt-target.js) | 14 | ||||
-rw-r--r-- | test/attributes/hx-trigger.js (renamed from test/attributes/kt-trigger.js) | 10 | ||||
-rw-r--r-- | test/core/ajax.js | 66 | ||||
-rw-r--r-- | test/core/api.js | 68 | ||||
-rw-r--r-- | test/core/events.js | 34 | ||||
-rw-r--r-- | test/core/headers.js | 18 | ||||
-rw-r--r-- | test/core/internals.js | 14 | ||||
-rw-r--r-- | test/core/parameters.js | 52 | ||||
-rw-r--r-- | test/core/regressions.js | 16 | ||||
-rw-r--r-- | test/core/verbs.js | 10 | ||||
-rw-r--r-- | test/index.html | 40 | ||||
-rw-r--r-- | test/manual/browser-only-tests.html | 10 | ||||
-rw-r--r-- | test/manual/confirm-and-prompt.html | 8 | ||||
-rw-r--r-- | test/manual/no-indicator-css.html | 6 | ||||
-rw-r--r-- | test/manual/yes-indicator-css.html | 4 | ||||
-rw-r--r-- | test/scratch.html | 12 | ||||
-rw-r--r-- | test/util/scratch_server.js | 6 | ||||
-rw-r--r-- | test/util/util.js | 4 | ||||
-rw-r--r-- | www/_includes/layout.njk | 20 | ||||
-rw-r--r-- | www/attributes/hx-boost.md (renamed from www/attributes/kt-boost.md) | 10 | ||||
-rw-r--r-- | www/attributes/hx-classes.md (renamed from www/attributes/kt-classes.md) | 20 | ||||
-rw-r--r-- | www/attributes/hx-confirm.md (renamed from www/attributes/kt-confirm.md) | 10 | ||||
-rw-r--r-- | www/attributes/hx-delete.md (renamed from www/attributes/kt-delete.md) | 16 | ||||
-rw-r--r-- | www/attributes/hx-error-url.md | 24 | ||||
-rw-r--r-- | www/attributes/hx-get.md | 25 | ||||
-rw-r--r-- | www/attributes/hx-history-elt.md (renamed from www/attributes/kt-history-elt.md) | 12 | ||||
-rw-r--r-- | www/attributes/hx-include.md (renamed from www/attributes/kt-include.md) | 10 | ||||
-rw-r--r-- | www/attributes/hx-indicator.md (renamed from www/attributes/kt-indicator.md) | 40 | ||||
-rw-r--r-- | www/attributes/hx-params.md (renamed from www/attributes/kt-params.md) | 10 | ||||
-rw-r--r-- | www/attributes/hx-patch.md (renamed from www/attributes/kt-patch.md) | 16 | ||||
-rw-r--r-- | www/attributes/hx-post.md | 25 | ||||
-rw-r--r-- | www/attributes/hx-prompt.md | 21 | ||||
-rw-r--r-- | www/attributes/hx-push-url.md | 26 | ||||
-rw-r--r-- | www/attributes/hx-put.md (renamed from www/attributes/kt-put.md) | 16 | ||||
-rw-r--r-- | www/attributes/hx-select.md (renamed from www/attributes/kt-select.md) | 10 | ||||
-rw-r--r-- | www/attributes/hx-sse-src.md (renamed from www/attributes/kt-sse-src.md) | 12 | ||||
-rw-r--r-- | www/attributes/hx-swap-oob.md (renamed from www/attributes/kt-swap-oob.md) | 12 | ||||
-rw-r--r-- | www/attributes/hx-swap.md (renamed from www/attributes/kt-swap.md) | 20 | ||||
-rw-r--r-- | www/attributes/hx-target.md (renamed from www/attributes/kt-target.md) | 10 | ||||
-rw-r--r-- | www/attributes/hx-trigger.md (renamed from www/attributes/kt-trigger.md) | 22 | ||||
-rw-r--r-- | www/attributes/kt-error-url.md | 24 | ||||
-rw-r--r-- | www/attributes/kt-get.md | 25 | ||||
-rw-r--r-- | www/attributes/kt-post.md | 25 | ||||
-rw-r--r-- | www/attributes/kt-prompt.md | 21 | ||||
-rw-r--r-- | www/attributes/kt-push-url.md | 26 | ||||
-rw-r--r-- | www/css/prism-htmx.css (renamed from www/css/prism-kutty.css) | 2 | ||||
-rw-r--r-- | www/docs.md | 264 | ||||
-rw-r--r-- | www/events.md | 66 | ||||
-rw-r--r-- | www/examples.md | 4 | ||||
-rw-r--r-- | www/examples/active-search.md | 22 | ||||
-rw-r--r-- | www/examples/bulk-update.md | 20 | ||||
-rw-r--r-- | www/examples/click-to-edit.md | 16 | ||||
-rw-r--r-- | www/examples/click-to-load.md | 16 | ||||
-rw-r--r-- | www/examples/infinite-scroll.md | 14 | ||||
-rw-r--r-- | www/examples/inline-validation.md | 26 | ||||
-rw-r--r-- | www/examples/lazy-load.md | 12 | ||||
-rw-r--r-- | www/examples/progress-bar.md | 38 | ||||
-rw-r--r-- | www/examples/value-select.md | 6 | ||||
-rw-r--r-- | www/headers/x-ht-trigger.md (renamed from www/headers/x-kt-trigger.md) | 16 | ||||
-rw-r--r-- | www/img/htmx_logo.2.png (renamed from www/img/kutty_logo.2.png) | bin | 15693 -> 15693 bytes | |||
-rw-r--r-- | www/img/kutty_placeholder.png | bin | 32478 -> 0 bytes | |||
-rw-r--r-- | www/index.md | 18 | ||||
-rw-r--r-- | www/js/kutty.js | 1306 | ||||
-rw-r--r-- | www/posts/2020-5-18-kutty-er-htmx-0.0.2-is-released.md | 38 | ||||
-rw-r--r-- | www/reference.md | 122 | ||||
-rw-r--r-- | www/talk.md | 10 |
90 files changed, 1062 insertions, 2330 deletions
@@ -1,28 +1,28 @@ - + *high power tools for HTML* ## Introduction Kutty is a set of extensions (attributes, request headers, etc.) that help you build -[modern UI](https://kutty.org/examples) with the [simplicity](https://en.wikipedia.org/wiki/HATEOAS) and +[modern UI](https://htmx.org/examples) with the [simplicity](https://en.wikipedia.org/wiki/HATEOAS) and [power](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) of HTML. -Kutty is small ([~6k min.gz'd](https://unpkg.com/kutty.org/dist/)), IE11 compatible, [dependency-free](https://github.com/bigskysoftware/kutty/blob/master/package.json) +Kutty is small ([~6k min.gz'd](https://unpkg.com/htmx.org/dist/)), IE11 compatible, [dependency-free](https://github.com/bigskysoftware/htmx/blob/master/package.json) & you can try it out quickly, without a huge rewrite. ## Quick Start ```html <!-- Load from unpkg --> - <script src="https://unpkg.com/kutty.org@0.0.2"></script> + <script src="https://unpkg.com/htmx.org@0.0.2"></script> <!-- have a button POST a click via AJAX --> - <button kt-post="/clicked" kt-swap="outerHTML"> + <button hx-post="/clicked" hx-swap="outerHTML"> Click Me </button> ``` -The `kt-post` and `kt-swap` attributes tell kutty: +The `hx-post` and `hx-swap` attributes tell htmx: > "When a user clicks on this button, issue an AJAX request to /example, and replace the entire button with the response" @@ -30,6 +30,6 @@ Kutty is based on [intercooler.js](http://intercoolerjs.org) and is the successo ## Website & Docs -[https://kutty.org](https://kutty.org) +[https://htmx.org](https://htmx.org) -[https://kutty.org/docs](https://kutty.org/docs) +[https://htmx.org/docs](https://htmx.org/docs) @@ -10,9 +10,9 @@ * Testing * interval parsing * scrolling/'revealed' event - * kt-swap-oob (verify, chrome coverage tool bad?) + * hx-swap-oob (verify, chrome coverage tool bad?) * SSE stuff - * kt-trigger delay + * hx-trigger delay * class operation parsing * class toggling * transition model for content swaps @@ -21,11 +21,11 @@ * logrithmic back off on history cache size on QuotaExceededError * ctrl-click on boosted anchors: tab opens normally -* `kutty-on="myEvent: ...""` attribute for handling custom events -* `kutty-requests` class on body -* local references (e.g. kt-get="#foo") +* `htmx-on="myEvent: ...""` attribute for handling custom events +* `htmx-requests` class on body +* local references (e.g. hx-get="#foo") * focus recapture -* Move to weakmap for kutty node info? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap +* Move to weakmap for htmx node info? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap * Scroll handler use https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API if available? ## Unsupported Intercooler Features diff --git a/dist/kutty.js b/dist/htmx.js index 35ce3150..12670f76 100644 --- a/dist/kutty.js +++ b/dist/htmx.js @@ -1,5 +1,5 @@ // noinspection JSUnusedAssignment -var kutty = kutty || (function () { +var htmx = kutty || (function () { 'use strict'; var VERBS = ['get', 'post', 'put', 'delete', 'patch'] @@ -285,9 +285,9 @@ var kutty = kutty || (function () { //==================================================================== function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getRawAttribute(e,"kt-target") !== null}); + var explicitTarget = getClosestMatch(elt, function(e){return getRawAttribute(e,"hx-target") !== null}); if (explicitTarget) { - var targetStr = getRawAttribute(explicitTarget, "kt-target"); + var targetStr = getRawAttribute(explicitTarget, "hx-target"); if (targetStr === "this") { return explicitTarget; } else if (targetStr.indexOf("closest ") === 0) { @@ -319,7 +319,7 @@ var kutty = kutty || (function () { function handleOutOfBandSwaps(fragment) { var settleTasks = []; forEach(fragment.children, function (child) { - if (getAttributeValue(child, "kt-swap-oob") === "true") { + if (getAttributeValue(child, "hx-swap-oob") === "true") { var target = getDocument().getElementById(child.id); if (target) { var fragment = getDocument().createDocumentFragment(); @@ -401,7 +401,7 @@ var kutty = kutty || (function () { } function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "kt-select"); + var selector = getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -454,7 +454,7 @@ var kutty = kutty || (function () { var triggerSpec = { "trigger" : "click" } - var explicitTrigger = getAttributeValue(elt, 'kt-trigger'); + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); if (explicitTrigger) { var tokens = splitOnWhitespace(explicitTrigger); if (tokens.length > 0) { @@ -548,7 +548,7 @@ var kutty = kutty || (function () { nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { issueAjaxRequest(elt, verb, path); - processPolling(elt, verb, getAttributeValue(elt, "kt-" + verb), interval); + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); } }, interval); } @@ -623,7 +623,7 @@ var kutty = kutty || (function () { function initScrollHandler() { if (!window['kuttyScrollHandler']) { var scrollHandler = function() { - forEach(getDocument().querySelectorAll("[kt-trigger='revealed']"), function (elt) { + forEach(getDocument().querySelectorAll("[hx-trigger='revealed']"), function (elt) { maybeReveal(elt); }); }; @@ -697,7 +697,7 @@ var kutty = kutty || (function () { function processVerbs(elt, nodeData, triggerSpec) { var explicitAction = false; forEach(VERBS, function (verb) { - var path = getAttributeValue(elt, 'kt-' + verb); + var path = getAttributeValue(elt, 'hx-' + verb); if (path) { explicitAction = true; nodeData.path = path; @@ -728,14 +728,14 @@ var kutty = kutty || (function () { var triggerSpec = getTriggerSpec(elt); var explicitAction = processVerbs(elt, nodeData, triggerSpec); - if (!explicitAction && getClosestAttributeValue(elt, "kt-boost") === "true") { + if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { boostElement(elt, nodeData, triggerSpec); } - var sseSrc = getAttributeValue(elt, 'kt-sse-source'); + var sseSrc = getAttributeValue(elt, 'hx-sse-source'); if (sseSrc) { initSSESource(elt, sseSrc); } - var addClass = getAttributeValue(elt, 'kt-classes'); + var addClass = getAttributeValue(elt, 'hx-classes'); if (addClass) { processClassList(elt, addClass); } @@ -750,7 +750,7 @@ var kutty = kutty || (function () { //==================================================================== function sendError(elt, eventName, detail) { - var errorURL = getClosestAttributeValue(elt, "kt-error-url"); + var errorURL = getClosestAttributeValue(elt, "hx-error-url"); if (errorURL) { var xhr = new XMLHttpRequest(); xhr.open("POST", errorURL); @@ -793,7 +793,7 @@ var kutty = kutty || (function () { var currentPathForHistory = null; function getHistoryElement() { - var historyElt = getDocument().querySelector('[kt-history-elt]'); + var historyElt = getDocument().querySelector('[hx-history-elt]'); return historyElt || getDocument().body; } @@ -850,7 +850,7 @@ var kutty = kutty || (function () { if (this.status >= 200 && this.status < 400) { triggerEvent(getDocument().body, "historyCacheMissLoad.kutty", details); var fragment = makeFragment(this.response); - fragment = fragment.querySelector('[kt-history-elt]') || fragment; + fragment = fragment.querySelector('[hx-history-elt]') || fragment; settleImmediately(swapInnerHTML(getHistoryElement(), fragment)); currentPathForHistory = path; } else { @@ -876,7 +876,7 @@ var kutty = kutty || (function () { } function shouldPush(elt) { - return getClosestAttributeValue(elt, "kt-push-url") === "true" || + return getClosestAttributeValue(elt, "hx-push-url") === "true" || (elt.tagName === "A" && getInternalData(elt).boosted); } @@ -889,7 +889,7 @@ var kutty = kutty || (function () { } function mutateRequestIndicatorClasses(elt, action) { - var indicator = getClosestAttributeValue(elt, 'kt-indicator'); + var indicator = getClosestAttributeValue(elt, 'hx-indicator'); if (indicator) { var indicators = getDocument().querySelectorAll(indicator); } else { @@ -965,7 +965,7 @@ var kutty = kutty || (function () { processInputValue(processed, values, elt); // include any explicit includes - var includes = getClosestAttributeValue(elt, "kt-include"); + var includes = getClosestAttributeValue(elt, "hx-include"); if (includes) { var nodes = getDocument().querySelectorAll(includes); forEach(nodes, function(node) { @@ -1034,7 +1034,7 @@ var kutty = kutty || (function () { } function filterValues(inputValues, elt, verb) { - var paramsValue = getClosestAttributeValue(elt, "kt-params"); + var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { if (paramsValue === "none") { return {}; @@ -1060,7 +1060,7 @@ var kutty = kutty || (function () { } function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "kt-swap"); + var swapInfo = getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { "swapStyle" : kutty.config.defaultSwapStyle, "swapDelay" : kutty.config.defaultSwapDelay, @@ -1087,7 +1087,7 @@ var kutty = kutty || (function () { function issueAjaxRequest(elt, verb, path, eventTarget) { var target = getTarget(elt); if (target == null) { - triggerErrorEvent(elt, 'targetError.kutty', {target: getRawAttribute(elt, "kt-target")}); + triggerErrorEvent(elt, 'targetError.kutty', {target: getRawAttribute(elt, "hx-target")}); return; } var eltData = getInternalData(elt); @@ -1099,13 +1099,13 @@ var kutty = kutty || (function () { var endRequestLock = function(){ eltData.requestInFlight = false } - var promptQuestion = getClosestAttributeValue(elt, "kt-prompt"); + var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); if (promptQuestion) { var prompt = prompt(promptQuestion); if(!triggerEvent(elt, 'prompt.kutty', {prompt: prompt, target:target})) return endRequestLock(); } - var confirmQuestion = getClosestAttributeValue(elt, "kt-confirm"); + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); if (confirmQuestion) { if(!confirm(confirmQuestion)) return endRequestLock(); } diff --git a/dist/kutty.min.js b/dist/htmx.min.js index 7d05ceec..755ba50e 100644 --- a/dist/kutty.min.js +++ b/dist/htmx.min.js @@ -1 +1 @@ -var kutty=kutty||function(){"use strict";var e=["get","post","put","delete","patch"];function u(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 k(e,t){return e.getAttribute&&e.getAttribute(t)}function l(e,t){return k(e,t)||k(e,"data-"+t)}function n(e){return e.parentElement}function o(){return document}function s(e,t){if(t(e)){return e}else if(n(e)){return s(n(e),t)}else{return null}}function b(e,t){var r=null;s(e,function(e){return r=k(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 i(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}return i}function c(e){var t=r(e);switch(t){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return i("<table>"+e+"</table>",1);case"col":return i("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return i("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return i("<table><tbody><tr>"+e+"</tr></tbody></table>",3);default:return i(e,0)}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function a(e){return t(e,"Function")}function v(e){return t(e,"Object")}function S(e){var t="kutty-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function w(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function d(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function y(e){return o().body.contains(e)}function g(e,t){return e.concat(t)}function h(e){return e.split(/\s+/)}function p(e){var t=o().styleSheets[0];t.insertRule(e,t.cssRules.length)}function m(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){return eval(e)}function T(t){var e=kutty.on("load.kutty",function(e){t(e.detail.elt)});return e}function C(){kutty.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function O(e,t){if(t){return e.querySelector(t)}else{return o().body.querySelector(e)}}function L(e,t){if(t){return e.querySelectorAll(t)}else{return o().body.querySelectorAll(e)}}function q(e,t){if(t){setTimeout(function(){q(e)},t)}else{e.parentElement.removeChild(e)}}function N(e,t,r){if(r){setTimeout(function(){N(e,t)},r)}else{e.classList.add(t)}}function x(e,t,r){if(r){setTimeout(function(){x(e,t)},r)}else{e.classList.remove(t)}}function A(e,t){e.classList.toggle(t)}function D(e,t){w(e.parentElement.children,function(e){x(e,t)});N(e,t)}function M(e,t){do{if(e==null||f(e,t))return e}while(e=e&&n(e))}function R(e,t,r){if(a(t)){return{target:o().body,event:e,listener:t}}else{return{target:e,event:t,listener:r}}}function X(t,r,n){Je(function(){var e=R(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=a(r);return e?r:n}function H(t,r,n){Je(function(){var e=R(t,r,n);e.target.removeEventListener(e.event,e.listener)});return a(r)?r:n}function I(e){var t=s(e,function(e){return k(e,"kt-target")!==null});if(t){var r=k(t,"kt-target");if(r==="this"){return t}else if(r.indexOf("closest ")===0){return M(e,r.substr(8))}else{return o().querySelector(r)}}else{var n=S(e);if(n.boosted){return o().body}else{return e}}}function F(t,r){w(t.attributes,function(e){if(!r.hasAttribute(e.name)){t.removeAttribute(e.name)}});w(r.attributes,function(e){t.setAttribute(e.name,e.value)})}function K(e){var n=[];w(e.children,function(e){if(l(e,"kt-swap-oob")==="true"){var t=o().getElementById(e.id);if(t){var r=o().createDocumentFragment();r.appendChild(e);n=n.concat(U(t,r))}else{e.parentNode.removeChild(e);he(o().body,"oobErrorNoTarget.kutty",{content:e})}}});return n}function P(n,e){var i=[];w(e.querySelectorAll("[id]"),function(e){var t=n.querySelector(e.tagName+"[id="+e.id+"]");if(t){var r=e.cloneNode();F(e,t);i.push(function(){F(e,r)})}});return i}function J(e,t,r){var n=P(e,r);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE){pe(i,"load.kutty",{});de(i)}}return n}function U(e,t){if(e.tagName==="BODY"){return G(e,t)}else{var r=J(n(e),e,t);n(e).removeChild(e);return r}}function j(e,t){return J(e,e.firstChild,t)}function z(e,t){return J(n(e),e,t)}function B(e,t){return J(e,null,t)}function V(e,t){return J(n(e),e.nextSibling,t)}function G(e,t){var r=e.firstChild;var n=J(e,r,t);if(r){while(r.nextSibling){e.removeChild(r.nextSibling)}e.removeChild(r)}return n}function Y(e,t){var r=b(e,"kt-select");if(r){var n=o().createDocumentFragment();w(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function _(e,t,r,n){var i=c(n);if(i){var a=K(i);i=Y(r,i);switch(e){case"outerHTML":return g(a,U(t,i));case"afterbegin":return g(a,j(t,i));case"beforebegin":return g(a,z(t,i));case"beforeend":return g(a,B(t,i));case"afterend":return g(a,V(t,i));default:return g(a,G(t,i))}}}function Q(e,t){if(t){if(t.indexOf("{")===0){var r=JSON.parse(t);for(var n in r){if(r.hasOwnProperty(n)){var i=r[n];if(!v(i)){i={value:i}}pe(e,n,i)}}}else{pe(e,t,[])}}}function W(e){var t={trigger:"click"};var r=l(e,"kt-trigger");if(r){var n=h(r);if(n.length>0){var i=n[0];if(i==="every"){t.pollInterval=u(n[1])}else if(i.indexOf("sse:")===0){t.sseEvent=i.substr(4)}else{t["trigger"]=i;for(var a=1;a<n.length;a++){var o=n[a].trim();if(o==="changed"){t.changed=true}if(o==="once"){t.once=true}if(o.indexOf("delay:")===0){t.delay=u(o.substr(6))}}}}}else{if(f(e,"form")){t["trigger"]="submit"}else if(f(e,"input, textarea, select")){t["trigger"]="change"}}return t}function Z(e){var t=h(e);if(t.length>1){var r=t[0];var n=t[1].trim();var i;var a;if(n.indexOf(":")>0){var o=n.split(":");i=o[0];a=u(o[1])}else{i=n;a=100}return{operation:r,cssClass:i,delay:a}}else{return null}}function $(i,e){w(e.split("&"),function(e){var n=0;w(e.split(","),function(e){var t=e.trim();var r=Z(t);if(r){if(r.operation==="toggle"){setTimeout(function(){setInterval(function(){i.classList[r.operation].call(i.classList,r.cssClass)},r.delay)},n);n=n+r.delay}else{n=n+r.delay;setTimeout(function(){i.classList[r.operation].call(i.classList,r.cssClass)},n)}}})})}function ee(e){S(e).cancelled=true}function te(e,t,r,n){var i=S(e);i.timeout=setTimeout(function(){if(y(e)&&i.cancelled!==true){Pe(e,t,r);te(e,t,l(e,"kt-"+t),n)}},n)}function re(e){return location.hostname===e.hostname&&k(e,"href")&&k(e,"href").indexOf("#")!==0}function ne(e,t,r){if(e.tagName==="A"&&re(e)||e.tagName==="FORM"){t.boosted=true;var n,i;if(e.tagName==="A"){n="get";i=k(e,"href")}else{var a=k(e,"method");n=a?a.toLowerCase():"get";i=k(e,"action")}ae(e,n,i,t,r,true)}}function ie(e){return e.tagName==="FORM"||f(e,'input[type="submit"], button')&&M(e,"form")!==null||e.tagName==="A"&&e.href&&e.href.indexOf("#")!==0}function ae(i,a,o,e,u,l){var t=function(e){if(l||ie(i))e.preventDefault();var t=S(e);var r=S(i);if(!t.handled){t.handled=true;if(u.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(u.changed){if(r.lastValue===i.value){return}else{r.lastValue=i.value}}if(r.delayed){clearTimeout(r.delayed)}var n=function(){Pe(i,a,o,e.target)};if(u.delay){r.delayed=setTimeout(n,u.delay)}else{n()}}};e.trigger=u.trigger;e.eventListener=t;i.addEventListener(u.trigger,t)}function oe(){if(!window["kuttyScrollHandler"]){var e=function(){w(o().querySelectorAll("[kt-trigger='revealed']"),function(e){ue(e)})};window["kuttyScrollHandler"]=e;window.addEventListener("scroll",e)}}function ue(e){var t=S(e);if(!t.revealed&&d(e)){t.revealed=true;Pe(e,t.verb,t.path)}}function le(e){if(!y(e)){e.sseSource.close();return true}}function se(t,e){var r={config:{withCredentials:true}};pe(t,"initSSE.kutty",r);var n=new EventSource(e,r.config);n.onerror=function(e){he(t,"sseError.kutty",{error:e,source:n});le(t)};S(t).sseSource=n}function fe(e,t,r,n){var i=s(e,function(e){return e.sseSource});if(i){var a=function(){if(!le(i)){if(y(e)){Pe(e,t,r)}else{i.sseSource.removeEventListener(n,a)}}};i.sseSource.addEventListener(n,a)}else{he(e,"noSSESourceError.kutty")}}function ce(e,t,r,n,i){var a=function(){if(!n.loaded){n.loaded=true;Pe(e,t,r)}};if(i){setTimeout(a,i)}else{a()}}function ve(r,n,i){var a=false;w(e,function(e){var t=l(r,"kt-"+e);if(t){a=true;n.path=t;n.verb=e;if(i.sseEvent){fe(r,e,t,i.sseEvent)}else if(i.trigger==="revealed"){oe();ue(r)}else if(i.trigger==="load"){ce(r,e,t,n,i.delay)}else if(i.pollInterval){n.polling=true;te(r,e,t,i.pollInterval)}else{ae(r,e,t,n,i)}}});return a}function de(e){var t=S(e);if(!t.processed){t.processed=true;var r=W(e);var n=ve(e,t,r);if(!n&&b(e,"kt-boost")==="true"){ne(e,t,r)}var i=l(e,"kt-sse-source");if(i){se(e,i)}var a=l(e,"kt-classes");if(a){$(e,a)}}if(e.children){w(e.children,function(e){de(e)})}}function ye(e,t,r){var n=b(e,"kt-error-url");if(n){var i=new XMLHttpRequest;i.open("POST",n);i.setRequestHeader("Content-Type","application/json;charset=UTF-8");i.send(JSON.stringify({elt:e.id,event:t,detail:r}))}}function ge(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=o().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function he(e,t,r){pe(e,t,m({isError:true},r))}function pe(e,t,r){r["elt"]=e;var n=ge(t,r);if(kutty.logger){kutty.logger(e,t,r);if(r.isError){ye(e,t,r)}}var i=e.dispatchEvent(n);return i}var me=null;function ke(){var e=o().querySelector("[kt-history-elt]");return e||o().body}function be(e,t,r,n){var i=JSON.parse(localStorage.getItem("kutty-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i=i.slice(a,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>kutty.config.historyCacheSize){i.shift()}localStorage.setItem("kutty-history-cache",JSON.stringify(i))}function Se(e){var t=JSON.parse(localStorage.getItem("kutty-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function we(){var e=ke();var t=me||location.pathname+location.search;pe(o().body,"beforeHistorySave.kutty",{path:t,historyElt:e});if(kutty.config.historyEnabled)history.replaceState({},o().title,window.location.href);be(t,e.innerHTML,o().title,window.scrollY)}function Ee(e){if(kutty.config.historyEnabled)history.pushState({},"",e);me=e}function Te(e){w(e,function(e){e.call()})}function Ce(t){var e=new XMLHttpRequest;var r={path:t,xhr:e};pe(o().body,"historyCacheMiss.kutty",r);e.open("GET",t,true);e.onload=function(){if(this.status>=200&&this.status<400){pe(o().body,"historyCacheMissLoad.kutty",r);var e=c(this.response);e=e.querySelector("[kt-history-elt]")||e;Te(G(ke(),e));me=t}else{he(o().body,"historyCacheMissLoadError.kutty",r)}};e.send()}function Oe(e){we(me);e=e||location.pathname+location.search;pe(o().body,"historyRestore.kutty",{path:e});var t=Se(e);if(t){Te(G(ke(),c(t.content)));document.title=t.title;window.scrollTo(0,t.scroll);me=e}else{Ce(e)}}function Le(e){return b(e,"kt-push-url")==="true"||e.tagName==="A"&&S(e).boosted}function qe(e){xe(e,"add")}function Ne(e){xe(e,"remove")}function xe(e,t){var r=b(e,"kt-indicator");if(r){var n=o().querySelectorAll(r)}else{n=[e]}w(n,function(e){e.classList[t].call(e.classList,"kutty-request")})}function Ae(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function De(e){if(e.name===""||e.name==null||e.disabled){return false}if(e.type==="button"||e.type==="submit"||e.tagName==="image"||e.tagName==="reset"||e.tagName==="file"){return false}if(e.type==="checkbox"||e.type==="radio"){return e.checked}return true}function Me(t,r,e){if(e==null||Ae(t,e)){return}else{t.push(e)}if(De(e)){var n=k(e,"name");var i=e.value;if(n&&i){var a=r[n];if(a){if(Array.isArray(a)){a.push(i)}else{r[n]=[a,i]}}else{r[n]=i}}}if(f(e,"form")){var o=e.elements;w(o,function(e){Me(t,r,e)})}}function Re(e,t){var r=[];var n={};Me(r,n,e);var i=b(e,"kt-include");if(i){var a=o().querySelectorAll(i);w(a,function(e){Me(r,n,e)})}if(t!=="get"){Me(r,n,M(e,"form"))}return n}function Xe(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function He(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){w(n,function(e){t=Xe(t,r,e)})}else{t=Xe(t,r,n)}}}return t}function Ie(e,t,r,n){var i={"X-KT-Request":"true","X-KT-Trigger":k(e,"id"),"X-KT-Trigger-Name":k(e,"name"),"X-KT-Target":k(t,"id"),"Current-URL":o().location.href};if(r){i["X-KT-Prompt"]=r}if(n){i["X-KT-Event-Target"]=k(n,"id")}if(o().activeElement){i["X-KT-Active-Element"]=k(o().activeElement,"id");i["X-KT-Active-Element-Name"]=k(o().activeElement,"name");if(o().activeElement.value){i["X-KT-Active-Element-Value"]=k(o().activeElement,"value")}}return i}function Fe(t,e,r){var n=b(e,"kt-params");if(n){if(n==="none"){return{}}else if(n==="*"){return t}else if(n.indexOf("not ")===0){w(n.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var i={};w(n.split(","),function(e){e=e.trim();i[e]=t[e]});return i}}else{return t}}function Ke(e){var t=b(e,"kt-swap");var r={swapStyle:kutty.config.defaultSwapStyle,swapDelay:kutty.config.defaultSwapDelay,settleDelay:kutty.config.defaultSettleDelay};if(t){var n=h(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var a=n[i];if(a.indexOf("swap:")===0){r["swapDelay"]=u(a.substr(5))}if(a.indexOf("settle:")===0){r["settleDelay"]=u(a.substr(7))}}}}return r}function Pe(o,e,t,r){var u=I(o);if(u==null){he(o,"targetError.kutty",{target:k(o,"kt-target")});return}var n=S(o);if(n.requestInFlight){return}else{n.requestInFlight=true}var l=function(){n.requestInFlight=false};var i=b(o,"kt-prompt");if(i){var a=a(i);if(!pe(o,"prompt.kutty",{prompt:a,target:u}))return l()}var s=b(o,"kt-confirm");if(s){if(!confirm(s))return l()}var f=new XMLHttpRequest;var c=Ie(o,u,a,r);var v=Re(o,e);var d=Fe(v,o,e);if(e!=="get"){c["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8";if(e!=="post"){c["X-HTTP-Method-Override"]=e.toUpperCase()}}var y={parameters:d,unfilteredParameters:v,headers:c,target:u,verb:e};if(!pe(o,"configRequest.kutty",y))return l();var g;if(e==="get"){var h=Object.keys(d).length===0;g=t+(h?"":"?"+He(d));f.open("GET",g,true)}else{g=t;f.open("POST",g,true)}f.overrideMimeType("text/html");for(var p in c){if(c.hasOwnProperty(p)){if(c[p])f.setRequestHeader(p,c[p])}}var m={xhr:f,target:u};f.onload=function(){try{if(!pe(o,"beforeOnLoad.kutty",m))return;Q(o,this.getResponseHeader("X-KT-Trigger"));var r=this.getResponseHeader("X-KT-Push");var n=Le(o)||r;if(this.status>=200&&this.status<400){if(this.status===286){ee(o)}if(this.status!==204){if(!pe(o,"beforeSwap.kutty",m))return;var i=this.response;if(n){we()}var a=Ke(o);u.classList.add("kutty-swapping");var e=function(){try{var e=_(a.swapStyle,u,o,i);u.classList.remove("kutty-swapping");u.classList.add("kutty-settling");pe(o,"afterSwap.kutty",m);var t=function(){w(e,function(e){e.call()});u.classList.remove("kutty-settling");if(n){Ee(r||g)}pe(o,"afterSettle.kutty",m)};if(a.settleDelay>0){setTimeout(t,a.settleDelay)}else{t()}}catch(e){he(o,"swapError.kutty",m);throw e}};if(a.swapDelay>0){setTimeout(e,a.swapDelay)}else{e()}}}else{he(o,"responseError.kutty",m)}}catch(e){m["exception"]=e;he(o,"onLoadError.kutty",m);throw e}finally{Ne(o);l();pe(o,"afterOnLoad.kutty",m)}};f.onerror=function(){Ne(o);he(o,"sendError.kutty",m);l()};if(!pe(o,"beforeRequest.kutty",m))return l();qe(o);f.send(e==="get"?null:He(d))}function Je(e){if(o().readyState!=="loading"){e()}else{o().addEventListener("DOMContentLoaded",e)}}p(".kutty-indicator{opacity:0;transition: opacity 200ms ease-in;}");p(".kutty-request .kutty-indicator{opacity:1}");p(".kutty-request.kutty-indicator{opacity:1}");function Ue(){var e=o().querySelector('meta[name="kutty-config"]');if(e){var t=JSON.parse(e.content);kutty.config=m(kutty.config,t)}}Je(function(){Ue();var e=o().body;de(e);pe(e,"load.kutty",{});window.onpopstate=function(){Oe()}});return{onLoad:T,process:de,on:X,off:H,trigger:pe,find:O,findAll:L,closest:M,remove:q,addClass:N,removeClass:x,toggleClass:A,takeClass:D,logAll:C,logger:null,config:{historyEnabled:true,historyCacheSize:10,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:100},version:"0.0.1",_:E}}();
\ No newline at end of file +var kutty=kutty||function(){"use strict";var e=["get","post","put","delete","patch"];function u(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 k(e,t){return e.getAttribute&&e.getAttribute(t)}function l(e,t){return k(e,t)||k(e,"data-"+t)}function n(e){return e.parentElement}function o(){return document}function s(e,t){if(t(e)){return e}else if(n(e)){return s(n(e),t)}else{return null}}function b(e,t){var r=null;s(e,function(e){return r=k(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 i(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}return i}function c(e){var t=r(e);switch(t){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return i("<table>"+e+"</table>",1);case"col":return i("<table><colgroup>"+e+"</colgroup></table>",2);case"tr":return i("<table><tbody>"+e+"</tbody></table>",2);case"td":case"th":return i("<table><tbody><tr>"+e+"</tr></tbody></table>",3);default:return i(e,0)}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function a(e){return t(e,"Function")}function v(e){return t(e,"Object")}function S(e){var t="kutty-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function w(e,t){if(e){for(var r=0;r<e.length;r++){t(e[r])}}}function d(e){var t=e.getBoundingClientRect();var r=t.top;var n=t.bottom;return r<window.innerHeight&&n>=0}function y(e){return o().body.contains(e)}function g(e,t){return e.concat(t)}function h(e){return e.split(/\s+/)}function p(e){var t=o().styleSheets[0];t.insertRule(e,t.cssRules.length)}function m(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function E(e){return eval(e)}function T(t){var e=kutty.on("load.kutty",function(e){t(e.detail.elt)});return e}function C(){kutty.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function O(e,t){if(t){return e.querySelector(t)}else{return o().body.querySelector(e)}}function L(e,t){if(t){return e.querySelectorAll(t)}else{return o().body.querySelectorAll(e)}}function q(e,t){if(t){setTimeout(function(){q(e)},t)}else{e.parentElement.removeChild(e)}}function N(e,t,r){if(r){setTimeout(function(){N(e,t)},r)}else{e.classList.add(t)}}function x(e,t,r){if(r){setTimeout(function(){x(e,t)},r)}else{e.classList.remove(t)}}function A(e,t){e.classList.toggle(t)}function D(e,t){w(e.parentElement.children,function(e){x(e,t)});N(e,t)}function M(e,t){do{if(e==null||f(e,t))return e}while(e=e&&n(e))}function R(e,t,r){if(a(t)){return{target:o().body,event:e,listener:t}}else{return{target:e,event:t,listener:r}}}function X(t,r,n){Je(function(){var e=R(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=a(r);return e?r:n}function H(t,r,n){Je(function(){var e=R(t,r,n);e.target.removeEventListener(e.event,e.listener)});return a(r)?r:n}function I(e){var t=s(e,function(e){return k(e,"hx-target")!==null});if(t){var r=k(t,"hx-target");if(r==="this"){return t}else if(r.indexOf("closest ")===0){return M(e,r.substr(8))}else{return o().querySelector(r)}}else{var n=S(e);if(n.boosted){return o().body}else{return e}}}function F(t,r){w(t.attributes,function(e){if(!r.hasAttribute(e.name)){t.removeAttribute(e.name)}});w(r.attributes,function(e){t.setAttribute(e.name,e.value)})}function K(e){var n=[];w(e.children,function(e){if(l(e,"hx-swap-oob")==="true"){var t=o().getElementById(e.id);if(t){var r=o().createDocumentFragment();r.appendChild(e);n=n.concat(U(t,r))}else{e.parentNode.removeChild(e);he(o().body,"oobErrorNoTarget.kutty",{content:e})}}});return n}function P(n,e){var i=[];w(e.querySelectorAll("[id]"),function(e){var t=n.querySelector(e.tagName+"[id="+e.id+"]");if(t){var r=e.cloneNode();F(e,t);i.push(function(){F(e,r)})}});return i}function J(e,t,r){var n=P(e,r);while(r.childNodes.length>0){var i=r.firstChild;e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE){pe(i,"load.kutty",{});de(i)}}return n}function U(e,t){if(e.tagName==="BODY"){return G(e,t)}else{var r=J(n(e),e,t);n(e).removeChild(e);return r}}function j(e,t){return J(e,e.firstChild,t)}function z(e,t){return J(n(e),e,t)}function B(e,t){return J(e,null,t)}function V(e,t){return J(n(e),e.nextSibling,t)}function G(e,t){var r=e.firstChild;var n=J(e,r,t);if(r){while(r.nextSibling){e.removeChild(r.nextSibling)}e.removeChild(r)}return n}function Y(e,t){var r=b(e,"hx-select");if(r){var n=o().createDocumentFragment();w(t.querySelectorAll(r),function(e){n.appendChild(e)});t=n}return t}function _(e,t,r,n){var i=c(n);if(i){var a=K(i);i=Y(r,i);switch(e){case"outerHTML":return g(a,U(t,i));case"afterbegin":return g(a,j(t,i));case"beforebegin":return g(a,z(t,i));case"beforeend":return g(a,B(t,i));case"afterend":return g(a,V(t,i));default:return g(a,G(t,i))}}}function Q(e,t){if(t){if(t.indexOf("{")===0){var r=JSON.parse(t);for(var n in r){if(r.hasOwnProperty(n)){var i=r[n];if(!v(i)){i={value:i}}pe(e,n,i)}}}else{pe(e,t,[])}}}function W(e){var t={trigger:"click"};var r=l(e,"hx-trigger");if(r){var n=h(r);if(n.length>0){var i=n[0];if(i==="every"){t.pollInterval=u(n[1])}else if(i.indexOf("sse:")===0){t.sseEvent=i.substr(4)}else{t["trigger"]=i;for(var a=1;a<n.length;a++){var o=n[a].trim();if(o==="changed"){t.changed=true}if(o==="once"){t.once=true}if(o.indexOf("delay:")===0){t.delay=u(o.substr(6))}}}}}else{if(f(e,"form")){t["trigger"]="submit"}else if(f(e,"input, textarea, select")){t["trigger"]="change"}}return t}function Z(e){var t=h(e);if(t.length>1){var r=t[0];var n=t[1].trim();var i;var a;if(n.indexOf(":")>0){var o=n.split(":");i=o[0];a=u(o[1])}else{i=n;a=100}return{operation:r,cssClass:i,delay:a}}else{return null}}function $(i,e){w(e.split("&"),function(e){var n=0;w(e.split(","),function(e){var t=e.trim();var r=Z(t);if(r){if(r.operation==="toggle"){setTimeout(function(){setInterval(function(){i.classList[r.operation].call(i.classList,r.cssClass)},r.delay)},n);n=n+r.delay}else{n=n+r.delay;setTimeout(function(){i.classList[r.operation].call(i.classList,r.cssClass)},n)}}})})}function ee(e){S(e).cancelled=true}function te(e,t,r,n){var i=S(e);i.timeout=setTimeout(function(){if(y(e)&&i.cancelled!==true){Pe(e,t,r);te(e,t,l(e,"hx-"+t),n)}},n)}function re(e){return location.hostname===e.hostname&&k(e,"href")&&k(e,"href").indexOf("#")!==0}function ne(e,t,r){if(e.tagName==="A"&&re(e)||e.tagName==="FORM"){t.boosted=true;var n,i;if(e.tagName==="A"){n="get";i=k(e,"href")}else{var a=k(e,"method");n=a?a.toLowerCase():"get";i=k(e,"action")}ae(e,n,i,t,r,true)}}function ie(e){return e.tagName==="FORM"||f(e,'input[type="submit"], button')&&M(e,"form")!==null||e.tagName==="A"&&e.href&&e.href.indexOf("#")!==0}function ae(i,a,o,e,u,l){var t=function(e){if(l||ie(i))e.preventDefault();var t=S(e);var r=S(i);if(!t.handled){t.handled=true;if(u.once){if(r.triggeredOnce){return}else{r.triggeredOnce=true}}if(u.changed){if(r.lastValue===i.value){return}else{r.lastValue=i.value}}if(r.delayed){clearTimeout(r.delayed)}var n=function(){Pe(i,a,o,e.target)};if(u.delay){r.delayed=setTimeout(n,u.delay)}else{n()}}};e.trigger=u.trigger;e.eventListener=t;i.addEventListener(u.trigger,t)}function oe(){if(!window["kuttyScrollHandler"]){var e=function(){w(o().querySelectorAll("[hx-trigger='revealed']"),function(e){ue(e)})};window["kuttyScrollHandler"]=e;window.addEventListener("scroll",e)}}function ue(e){var t=S(e);if(!t.revealed&&d(e)){t.revealed=true;Pe(e,t.verb,t.path)}}function le(e){if(!y(e)){e.sseSource.close();return true}}function se(t,e){var r={config:{withCredentials:true}};pe(t,"initSSE.kutty",r);var n=new EventSource(e,r.config);n.onerror=function(e){he(t,"sseError.kutty",{error:e,source:n});le(t)};S(t).sseSource=n}function fe(e,t,r,n){var i=s(e,function(e){return e.sseSource});if(i){var a=function(){if(!le(i)){if(y(e)){Pe(e,t,r)}else{i.sseSource.removeEventListener(n,a)}}};i.sseSource.addEventListener(n,a)}else{he(e,"noSSESourceError.kutty")}}function ce(e,t,r,n,i){var a=function(){if(!n.loaded){n.loaded=true;Pe(e,t,r)}};if(i){setTimeout(a,i)}else{a()}}function ve(r,n,i){var a=false;w(e,function(e){var t=l(r,"hx-"+e);if(t){a=true;n.path=t;n.verb=e;if(i.sseEvent){fe(r,e,t,i.sseEvent)}else if(i.trigger==="revealed"){oe();ue(r)}else if(i.trigger==="load"){ce(r,e,t,n,i.delay)}else if(i.pollInterval){n.polling=true;te(r,e,t,i.pollInterval)}else{ae(r,e,t,n,i)}}});return a}function de(e){var t=S(e);if(!t.processed){t.processed=true;var r=W(e);var n=ve(e,t,r);if(!n&&b(e,"hx-boost")==="true"){ne(e,t,r)}var i=l(e,"hx-sse-source");if(i){se(e,i)}var a=l(e,"hx-classes");if(a){$(e,a)}}if(e.children){w(e.children,function(e){de(e)})}}function ye(e,t,r){var n=b(e,"hx-error-url");if(n){var i=new XMLHttpRequest;i.open("POST",n);i.setRequestHeader("Content-Type","application/json;charset=UTF-8");i.send(JSON.stringify({elt:e.id,event:t,detail:r}))}}function ge(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=o().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function he(e,t,r){pe(e,t,m({isError:true},r))}function pe(e,t,r){r["elt"]=e;var n=ge(t,r);if(kutty.logger){kutty.logger(e,t,r);if(r.isError){ye(e,t,r)}}var i=e.dispatchEvent(n);return i}var me=null;function ke(){var e=o().querySelector("[hx-history-elt]");return e||o().body}function be(e,t,r,n){var i=JSON.parse(localStorage.getItem("kutty-history-cache"))||[];for(var a=0;a<i.length;a++){if(i[a].url===e){i=i.slice(a,1);break}}i.push({url:e,content:t,title:r,scroll:n});while(i.length>kutty.config.historyCacheSize){i.shift()}localStorage.setItem("kutty-history-cache",JSON.stringify(i))}function Se(e){var t=JSON.parse(localStorage.getItem("kutty-history-cache"))||[];for(var r=0;r<t.length;r++){if(t[r].url===e){return t[r]}}return null}function we(){var e=ke();var t=me||location.pathname+location.search;pe(o().body,"beforeHistorySave.kutty",{path:t,historyElt:e});if(kutty.config.historyEnabled)history.replaceState({},o().title,window.location.href);be(t,e.innerHTML,o().title,window.scrollY)}function Ee(e){if(kutty.config.historyEnabled)history.pushState({},"",e);me=e}function Te(e){w(e,function(e){e.call()})}function Ce(t){var e=new XMLHttpRequest;var r={path:t,xhr:e};pe(o().body,"historyCacheMiss.kutty",r);e.open("GET",t,true);e.onload=function(){if(this.status>=200&&this.status<400){pe(o().body,"historyCacheMissLoad.kutty",r);var e=c(this.response);e=e.querySelector("[hx-history-elt]")||e;Te(G(ke(),e));me=t}else{he(o().body,"historyCacheMissLoadError.kutty",r)}};e.send()}function Oe(e){we(me);e=e||location.pathname+location.search;pe(o().body,"historyRestore.kutty",{path:e});var t=Se(e);if(t){Te(G(ke(),c(t.content)));document.title=t.title;window.scrollTo(0,t.scroll);me=e}else{Ce(e)}}function Le(e){return b(e,"hx-push-url")==="true"||e.tagName==="A"&&S(e).boosted}function qe(e){xe(e,"add")}function Ne(e){xe(e,"remove")}function xe(e,t){var r=b(e,"hx-indicator");if(r){var n=o().querySelectorAll(r)}else{n=[e]}w(n,function(e){e.classList[t].call(e.classList,"kutty-request")})}function Ae(e,t){for(var r=0;r<e.length;r++){var n=e[r];if(n.isSameNode(t)){return true}}return false}function De(e){if(e.name===""||e.name==null||e.disabled){return false}if(e.type==="button"||e.type==="submit"||e.tagName==="image"||e.tagName==="reset"||e.tagName==="file"){return false}if(e.type==="checkbox"||e.type==="radio"){return e.checked}return true}function Me(t,r,e){if(e==null||Ae(t,e)){return}else{t.push(e)}if(De(e)){var n=k(e,"name");var i=e.value;if(n&&i){var a=r[n];if(a){if(Array.isArray(a)){a.push(i)}else{r[n]=[a,i]}}else{r[n]=i}}}if(f(e,"form")){var o=e.elements;w(o,function(e){Me(t,r,e)})}}function Re(e,t){var r=[];var n={};Me(r,n,e);var i=b(e,"hx-include");if(i){var a=o().querySelectorAll(i);w(a,function(e){Me(r,n,e)})}if(t!=="get"){Me(r,n,M(e,"form"))}return n}function Xe(e,t,r){if(e!==""){e+="&"}e+=encodeURIComponent(t)+"="+encodeURIComponent(r);return e}function He(e){var t="";for(var r in e){if(e.hasOwnProperty(r)){var n=e[r];if(Array.isArray(n)){w(n,function(e){t=Xe(t,r,e)})}else{t=Xe(t,r,n)}}}return t}function Ie(e,t,r,n){var i={"X-KT-Request":"true","X-KT-Trigger":k(e,"id"),"X-KT-Trigger-Name":k(e,"name"),"X-KT-Target":k(t,"id"),"Current-URL":o().location.href};if(r){i["X-KT-Prompt"]=r}if(n){i["X-KT-Event-Target"]=k(n,"id")}if(o().activeElement){i["X-KT-Active-Element"]=k(o().activeElement,"id");i["X-KT-Active-Element-Name"]=k(o().activeElement,"name");if(o().activeElement.value){i["X-KT-Active-Element-Value"]=k(o().activeElement,"value")}}return i}function Fe(t,e,r){var n=b(e,"hx-params");if(n){if(n==="none"){return{}}else if(n==="*"){return t}else if(n.indexOf("not ")===0){w(n.substr(4).split(","),function(e){e=e.trim();delete t[e]});return t}else{var i={};w(n.split(","),function(e){e=e.trim();i[e]=t[e]});return i}}else{return t}}function Ke(e){var t=b(e,"hx-swap");var r={swapStyle:kutty.config.defaultSwapStyle,swapDelay:kutty.config.defaultSwapDelay,settleDelay:kutty.config.defaultSettleDelay};if(t){var n=h(t);if(n.length>0){r["swapStyle"]=n[0];for(var i=1;i<n.length;i++){var a=n[i];if(a.indexOf("swap:")===0){r["swapDelay"]=u(a.substr(5))}if(a.indexOf("settle:")===0){r["settleDelay"]=u(a.substr(7))}}}}return r}function Pe(o,e,t,r){var u=I(o);if(u==null){he(o,"targetError.kutty",{target:k(o,"hx-target")});return}var n=S(o);if(n.requestInFlight){return}else{n.requestInFlight=true}var l=function(){n.requestInFlight=false};var i=b(o,"hx-prompt");if(i){var a=a(i);if(!pe(o,"prompt.kutty",{prompt:a,target:u}))return l()}var s=b(o,"hx-confirm");if(s){if(!confirm(s))return l()}var f=new XMLHttpRequest;var c=Ie(o,u,a,r);var v=Re(o,e);var d=Fe(v,o,e);if(e!=="get"){c["Content-Type"]="application/x-www-form-urlencoded; charset=UTF-8";if(e!=="post"){c["X-HTTP-Method-Override"]=e.toUpperCase()}}var y={parameters:d,unfilteredParameters:v,headers:c,target:u,verb:e};if(!pe(o,"configRequest.kutty",y))return l();var g;if(e==="get"){var h=Object.keys(d).length===0;g=t+(h?"":"?"+He(d));f.open("GET",g,true)}else{g=t;f.open("POST",g,true)}f.overrideMimeType("text/html");for(var p in c){if(c.hasOwnProperty(p)){if(c[p])f.setRequestHeader(p,c[p])}}var m={xhr:f,target:u};f.onload=function(){try{if(!pe(o,"beforeOnLoad.kutty",m))return;Q(o,this.getResponseHeader("X-KT-Trigger"));var r=this.getResponseHeader("X-KT-Push");var n=Le(o)||r;if(this.status>=200&&this.status<400){if(this.status===286){ee(o)}if(this.status!==204){if(!pe(o,"beforeSwap.kutty",m))return;var i=this.response;if(n){we()}var a=Ke(o);u.classList.add("kutty-swapping");var e=function(){try{var e=_(a.swapStyle,u,o,i);u.classList.remove("kutty-swapping");u.classList.add("kutty-settling");pe(o,"afterSwap.kutty",m);var t=function(){w(e,function(e){e.call()});u.classList.remove("kutty-settling");if(n){Ee(r||g)}pe(o,"afterSettle.kutty",m)};if(a.settleDelay>0){setTimeout(t,a.settleDelay)}else{t()}}catch(e){he(o,"swapError.kutty",m);throw e}};if(a.swapDelay>0){setTimeout(e,a.swapDelay)}else{e()}}}else{he(o,"responseError.kutty",m)}}catch(e){m["exception"]=e;he(o,"onLoadError.kutty",m);throw e}finally{Ne(o);l();pe(o,"afterOnLoad.kutty",m)}};f.onerror=function(){Ne(o);he(o,"sendError.kutty",m);l()};if(!pe(o,"beforeRequest.kutty",m))return l();qe(o);f.send(e==="get"?null:He(d))}function Je(e){if(o().readyState!=="loading"){e()}else{o().addEventListener("DOMContentLoaded",e)}}p(".kutty-indicator{opacity:0;transition: opacity 200ms ease-in;}");p(".kutty-request .kutty-indicator{opacity:1}");p(".kutty-request.kutty-indicator{opacity:1}");function Ue(){var e=o().querySelector('meta[name="kutty-config"]');if(e){var t=JSON.parse(e.content);kutty.config=m(kutty.config,t)}}Je(function(){Ue();var e=o().body;de(e);pe(e,"load.kutty",{});window.onpopstate=function(){Oe()}});return{onLoad:T,process:de,on:X,off:H,trigger:pe,find:O,findAll:L,closest:M,remove:q,addClass:N,removeClass:x,toggleClass:A,takeClass:D,logAll:C,logger:null,config:{historyEnabled:true,historyCacheSize:10,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:100},version:"0.0.1",_:E}}();
\ No newline at end of file diff --git a/dist/kutty.min.js.gz b/dist/htmx.min.js.gz Binary files differindex c9135954..c9135954 100644 --- a/dist/kutty.min.js.gz +++ b/dist/htmx.min.js.gz diff --git a/package-lock.json b/package-lock.json index 5088c553..e0bcce21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "kutty.org", + "name": "htmx.org", "version": "0.0.1", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index 52b8305c..0dc0c21e 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { - "name": "kutty.org", + "name": "htmx.org", "description": "high power tools for html", "keywords": [ "AJAX", "HTML" ], - "version": "0.0.2", - "homepage": "https://kutty.org/", + "version": "0.0.3", + "homepage": "https://htmx.org/", "bugs": { - "url": "https://github.com/bigskysoftware/kutty/issues" + "url": "https://github.com/bigskysoftware/htmx/issues" }, "license": "BSD 2-Clause", "files": [ @@ -17,17 +17,17 @@ "dist/*.js", "dist/*.js.gz" ], - "main": "dist/kutty.min.js", - "unpkg": "dist/kutty.min.js", + "main": "dist/htmx.min.js", + "unpkg": "dist/htmx.min.js", "scripts": { "test": "mocha-chrome test/index.html", - "dist": "cp src/kutty.js dist/ && npm run-script uglify && gzip -k -f dist/kutty.min.js > dist/kutty.min.js.gz && exit", + "dist": "cp src/htmx.js dist/ && npm run-script uglify && gzip -k -f dist/htmx.min.js > dist/htmx.min.js.gz && exit", "www": "node scripts/www.js", - "uglify": "uglifyjs -m eval -o dist/kutty.min.js dist/kutty.js" + "uglify": "uglifyjs -m eval -o dist/htmx.min.js dist/htmx.js" }, "repository": { "type": "git", - "url": "git+https://github.com/bigskysoftware/kutty.git" + "url": "git+https://github.com/bigskysoftware/htmx.git" }, "devDependencies": { "@11ty/eleventy": "^0.10.0", diff --git a/scripts/www.js b/scripts/www.js index d932bc40..f60d9135 100644 --- a/scripts/www.js +++ b/scripts/www.js @@ -11,4 +11,4 @@ fs.copySync("node_modules/chai/chai.js", testRoot + "/node_modules/chai/chai.js" fs.copySync("node_modules/sinon/pkg/sinon.js", testRoot + "/node_modules/sinon/pkg/sinon.js"); fs.copySync("test/", testRoot + "/test"); fs.copySync("src/", testRoot + "/src"); -fs.copySync("src/kutty.js", "www/js/kutty.js");
\ No newline at end of file +fs.copySync("src/htmx.js", "www/js/htmx.js");
\ No newline at end of file diff --git a/src/kutty.js b/src/htmx.js index dee25f72..1d0137cd 100644 --- a/src/kutty.js +++ b/src/htmx.js @@ -1,5 +1,5 @@ // noinspection JSUnusedAssignment -var kutty = kutty || (function () { +var htmx = htmx || (function () { 'use strict'; var VERBS = ['get', 'post', 'put', 'delete', 'patch'] @@ -118,7 +118,7 @@ var kutty = kutty || (function () { } function getInternalData(elt) { - var dataProp = 'kutty-internal-data'; + var dataProp = 'htmx-internal-data'; var data = elt[dataProp]; if (!data) { data = elt[dataProp] = {}; @@ -181,14 +181,14 @@ var kutty = kutty || (function () { } function onLoadHelper(callback) { - var value = kutty.on("load.kutty", function(evt) { + var value = htmx.on("load.htmx", function(evt) { callback(evt.detail.elt); }); return value; } function logAll(){ - kutty.logger = function(elt, event, data) { + htmx.logger = function(elt, event, data) { if(console) { console.log(event, elt, data); } @@ -290,9 +290,9 @@ var kutty = kutty || (function () { //==================================================================== function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getRawAttribute(e,"kt-target") !== null}); + var explicitTarget = getClosestMatch(elt, function(e){return getRawAttribute(e,"hx-target") !== null}); if (explicitTarget) { - var targetStr = getRawAttribute(explicitTarget, "kt-target"); + var targetStr = getRawAttribute(explicitTarget, "hx-target"); if (targetStr === "this") { return explicitTarget; } else if (targetStr.indexOf("closest ") === 0) { @@ -324,7 +324,7 @@ var kutty = kutty || (function () { function handleOutOfBandSwaps(fragment) { var settleTasks = []; forEach(toArray(fragment.children), function (child) { - if (getAttributeValue(child, "kt-swap-oob") === "true") { + if (getAttributeValue(child, "hx-swap-oob") === "true") { var target = getDocument().getElementById(child.id); if (target) { var fragment = getDocument().createDocumentFragment(); @@ -332,7 +332,7 @@ var kutty = kutty || (function () { settleTasks = settleTasks.concat(swapOuterHTML(target, fragment)); } else { child.parentNode.removeChild(child); - triggerErrorEvent(getDocument().body, "oobErrorNoTarget.kutty", {content: child}) + triggerErrorEvent(getDocument().body, "oobErrorNoTarget.htmx", {content: child}) } } }); @@ -360,7 +360,7 @@ var kutty = kutty || (function () { var child = fragment.firstChild; parentNode.insertBefore(child, insertBefore); if (child.nodeType !== Node.TEXT_NODE) { - triggerEvent(child, 'load.kutty', {}); + triggerEvent(child, 'load.htmx', {}); processNode(child); } } @@ -406,7 +406,7 @@ var kutty = kutty || (function () { } function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "kt-select"); + var selector = getClosestAttributeValue(elt, "hx-select"); if (selector) { var newFragment = getDocument().createDocumentFragment(); forEach(fragment.querySelectorAll(selector), function (node) { @@ -459,7 +459,7 @@ var kutty = kutty || (function () { var triggerSpec = { "trigger" : "click" } - var explicitTrigger = getAttributeValue(elt, 'kt-trigger'); + var explicitTrigger = getAttributeValue(elt, 'hx-trigger'); if (explicitTrigger) { var tokens = splitOnWhitespace(explicitTrigger); if (tokens.length > 0) { @@ -553,7 +553,7 @@ var kutty = kutty || (function () { nodeData.timeout = setTimeout(function () { if (bodyContains(elt) && nodeData.cancelled !== true) { issueAjaxRequest(elt, verb, path); - processPolling(elt, verb, getAttributeValue(elt, "kt-" + verb), interval); + processPolling(elt, verb, getAttributeValue(elt, "hx-" + verb), interval); } }, interval); } @@ -626,13 +626,13 @@ var kutty = kutty || (function () { } function initScrollHandler() { - if (!window['kuttyScrollHandler']) { + if (!window['htmxScrollHandler']) { var scrollHandler = function() { - forEach(getDocument().querySelectorAll("[kt-trigger='revealed']"), function (elt) { + forEach(getDocument().querySelectorAll("[hx-trigger='revealed']"), function (elt) { maybeReveal(elt); }); }; - window['kuttyScrollHandler'] = scrollHandler; + window['htmxScrollHandler'] = scrollHandler; window.addEventListener("scroll", scrollHandler) } } @@ -656,10 +656,10 @@ var kutty = kutty || (function () { var detail = { config:{withCredentials: true} }; - triggerEvent(elt, "initSSE.kutty", detail); + triggerEvent(elt, "initSSE.htmx", detail); var source = new EventSource(sseSrc, detail.config); source.onerror = function (e) { - triggerErrorEvent(elt, "sseError.kutty", {error:e, source:source}); + triggerErrorEvent(elt, "sseError.htmx", {error:e, source:source}); maybeCloseSSESource(elt); }; getInternalData(elt).sseSource = source; @@ -681,7 +681,7 @@ var kutty = kutty || (function () { }; sseSource.sseSource.addEventListener(sseEventName, sseListener); } else { - triggerErrorEvent(elt, "noSSESourceError.kutty") + triggerErrorEvent(elt, "noSSESourceError.htmx") } } @@ -702,7 +702,7 @@ var kutty = kutty || (function () { function processVerbs(elt, nodeData, triggerSpec) { var explicitAction = false; forEach(VERBS, function (verb) { - var path = getAttributeValue(elt, 'kt-' + verb); + var path = getAttributeValue(elt, 'hx-' + verb); if (path) { explicitAction = true; nodeData.path = path; @@ -733,14 +733,14 @@ var kutty = kutty || (function () { var triggerSpec = getTriggerSpec(elt); var explicitAction = processVerbs(elt, nodeData, triggerSpec); - if (!explicitAction && getClosestAttributeValue(elt, "kt-boost") === "true") { + if (!explicitAction && getClosestAttributeValue(elt, "hx-boost") === "true") { boostElement(elt, nodeData, triggerSpec); } - var sseSrc = getAttributeValue(elt, 'kt-sse-source'); + var sseSrc = getAttributeValue(elt, 'hx-sse-source'); if (sseSrc) { initSSESource(elt, sseSrc); } - var addClass = getAttributeValue(elt, 'kt-classes'); + var addClass = getAttributeValue(elt, 'hx-classes'); if (addClass) { processClassList(elt, addClass); } @@ -755,7 +755,7 @@ var kutty = kutty || (function () { //==================================================================== function sendError(elt, eventName, detail) { - var errorURL = getClosestAttributeValue(elt, "kt-error-url"); + var errorURL = getClosestAttributeValue(elt, "hx-error-url"); if (errorURL) { var xhr = new XMLHttpRequest(); xhr.open("POST", errorURL); @@ -782,8 +782,8 @@ var kutty = kutty || (function () { function triggerEvent(elt, eventName, detail) { detail["elt"] = elt; var event = makeEvent(eventName, detail); - if (kutty.logger) { - kutty.logger(elt, eventName, detail); + if (htmx.logger) { + htmx.logger(elt, eventName, detail); if (detail.isError) { sendError(elt, eventName, detail); } @@ -798,12 +798,12 @@ var kutty = kutty || (function () { var currentPathForHistory = null; function getHistoryElement() { - var historyElt = getDocument().querySelector('[kt-history-elt]'); + var historyElt = getDocument().querySelector('[hx-history-elt]'); return historyElt || getDocument().body; } function saveToHistoryCache(url, content, title, scroll) { - var historyCache = JSON.parse(localStorage.getItem("kutty-history-cache")) || []; + var historyCache = JSON.parse(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { historyCache = historyCache.slice(i, 1); @@ -811,14 +811,14 @@ var kutty = kutty || (function () { } } historyCache.push({url:url, content: content, title:title, scroll:scroll}) - while (historyCache.length > kutty.config.historyCacheSize) { + while (historyCache.length > htmx.config.historyCacheSize) { historyCache.shift(); } - localStorage.setItem("kutty-history-cache", JSON.stringify(historyCache)); + localStorage.setItem("htmx-history-cache", JSON.stringify(historyCache)); } function getCachedHistory(url) { - var historyCache = JSON.parse(localStorage.getItem("kutty-history-cache")) || []; + var historyCache = JSON.parse(localStorage.getItem("htmx-history-cache")) || []; for (var i = 0; i < historyCache.length; i++) { if (historyCache[i].url === url) { return historyCache[i]; @@ -830,13 +830,13 @@ var kutty = kutty || (function () { function saveHistory() { var elt = getHistoryElement(); var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "beforeHistorySave.kutty", {path:path, historyElt:elt}); - if(kutty.config.historyEnabled) history.replaceState({}, getDocument().title, window.location.href); + triggerEvent(getDocument().body, "beforeHistorySave.htmx", {path:path, historyElt:elt}); + if(htmx.config.historyEnabled) history.replaceState({}, getDocument().title, window.location.href); saveToHistoryCache(path, elt.innerHTML, getDocument().title, window.scrollY); } function pushUrlIntoHistory(path) { - if(kutty.config.historyEnabled) history.pushState({}, "", path); + if(htmx.config.historyEnabled) history.pushState({}, "", path); currentPathForHistory = path; } @@ -849,17 +849,17 @@ var kutty = kutty || (function () { function loadHistoryFromServer(path) { var request = new XMLHttpRequest(); var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "historyCacheMiss.kutty", details); + triggerEvent(getDocument().body, "historyCacheMiss.htmx", details); request.open('GET', path, true); request.onload = function () { if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "historyCacheMissLoad.kutty", details); + triggerEvent(getDocument().body, "historyCacheMissLoad.htmx", details); var fragment = makeFragment(this.response); - fragment = fragment.querySelector('[kt-history-elt]') || fragment; + fragment = fragment.querySelector('[hx-history-elt]') || fragment; settleImmediately(swapInnerHTML(getHistoryElement(), fragment)); currentPathForHistory = path; } else { - triggerErrorEvent(getDocument().body, "historyCacheMissLoadError.kutty", details); + triggerErrorEvent(getDocument().body, "historyCacheMissLoadError.htmx", details); } }; request.send(); @@ -868,7 +868,7 @@ var kutty = kutty || (function () { function restoreHistory(path) { saveHistory(currentPathForHistory); path = path || location.pathname+location.search; - triggerEvent(getDocument().body, "historyRestore.kutty", {path:path}); + triggerEvent(getDocument().body, "historyRestore.htmx", {path:path}); var cached = getCachedHistory(path); if (cached) { settleImmediately(swapInnerHTML(getHistoryElement(), makeFragment(cached.content))); @@ -881,7 +881,7 @@ var kutty = kutty || (function () { } function shouldPush(elt) { - return getClosestAttributeValue(elt, "kt-push-url") === "true" || + return getClosestAttributeValue(elt, "hx-push-url") === "true" || (elt.tagName === "A" && getInternalData(elt).boosted); } @@ -894,14 +894,14 @@ var kutty = kutty || (function () { } function mutateRequestIndicatorClasses(elt, action) { - var indicator = getClosestAttributeValue(elt, 'kt-indicator'); + var indicator = getClosestAttributeValue(elt, 'hx-indicator'); if (indicator) { var indicators = getDocument().querySelectorAll(indicator); } else { indicators = [elt]; } forEach(indicators, function(ic) { - ic.classList[action].call(ic.classList, "kutty-request"); + ic.classList[action].call(ic.classList, "htmx-request"); }); } @@ -970,7 +970,7 @@ var kutty = kutty || (function () { processInputValue(processed, values, elt); // include any explicit includes - var includes = getClosestAttributeValue(elt, "kt-include"); + var includes = getClosestAttributeValue(elt, "hx-include"); if (includes) { var nodes = getDocument().querySelectorAll(includes); forEach(nodes, function(node) { @@ -1016,30 +1016,30 @@ var kutty = kutty || (function () { function getHeaders(elt, target, prompt, eventTarget) { var headers = { - "X-KT-Request" : "true", - "X-KT-Trigger" : getRawAttribute(elt, "id"), - "X-KT-Trigger-Name" : getRawAttribute(elt, "name"), - "X-KT-Target" : getRawAttribute(target, "id"), + "X-HX-Request" : "true", + "X-HX-Trigger" : getRawAttribute(elt, "id"), + "X-HX-Trigger-Name" : getRawAttribute(elt, "name"), + "X-HX-Target" : getRawAttribute(target, "id"), "Current-URL" : getDocument().location.href, } if (prompt) { - headers["X-KT-Prompt"] = prompt; + headers["X-HX-Prompt"] = prompt; } if (eventTarget) { - headers["X-KT-Event-Target"] = getRawAttribute(eventTarget, "id"); + headers["X-HX-Event-Target"] = getRawAttribute(eventTarget, "id"); } if (getDocument().activeElement) { - headers["X-KT-Active-Element"] = getRawAttribute(getDocument().activeElement, "id"); - headers["X-KT-Active-Element-Name"] = getRawAttribute(getDocument().activeElement, "name"); + headers["X-HX-Active-Element"] = getRawAttribute(getDocument().activeElement, "id"); + headers["X-HX-Active-Element-Name"] = getRawAttribute(getDocument().activeElement, "name"); if (getDocument().activeElement.value) { - headers["X-KT-Active-Element-Value"] = getRawAttribute(getDocument().activeElement, "value"); + headers["X-HX-Active-Element-Value"] = getRawAttribute(getDocument().activeElement, "value"); } } return headers; } function filterValues(inputValues, elt, verb) { - var paramsValue = getClosestAttributeValue(elt, "kt-params"); + var paramsValue = getClosestAttributeValue(elt, "hx-params"); if (paramsValue) { if (paramsValue === "none") { return {}; @@ -1065,11 +1065,11 @@ var kutty = kutty || (function () { } function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "kt-swap"); + var swapInfo = getClosestAttributeValue(elt, "hx-swap"); var swapSpec = { - "swapStyle" : kutty.config.defaultSwapStyle, - "swapDelay" : kutty.config.defaultSwapDelay, - "settleDelay" : kutty.config.defaultSettleDelay + "swapStyle" : htmx.config.defaultSwapStyle, + "swapDelay" : htmx.config.defaultSwapDelay, + "settleDelay" : htmx.config.defaultSettleDelay } if (swapInfo) { var split = splitOnWhitespace(swapInfo); @@ -1092,7 +1092,7 @@ var kutty = kutty || (function () { function issueAjaxRequest(elt, verb, path, eventTarget) { var target = getTarget(elt); if (target == null) { - triggerErrorEvent(elt, 'targetError.kutty', {target: getRawAttribute(elt, "kt-target")}); + triggerErrorEvent(elt, 'targetError.htmx', {target: getRawAttribute(elt, "hx-target")}); return; } var eltData = getInternalData(elt); @@ -1104,13 +1104,13 @@ var kutty = kutty || (function () { var endRequestLock = function(){ eltData.requestInFlight = false } - var promptQuestion = getClosestAttributeValue(elt, "kt-prompt"); + var promptQuestion = getClosestAttributeValue(elt, "hx-prompt"); if (promptQuestion) { var promptResponse = prompt(promptQuestion); - if(!triggerEvent(elt, 'prompt.kutty', {prompt: promptResponse, target:target})) return endRequestLock(); + if(!triggerEvent(elt, 'prompt.htmx', {prompt: promptResponse, target:target})) return endRequestLock(); } - var confirmQuestion = getClosestAttributeValue(elt, "kt-confirm"); + var confirmQuestion = getClosestAttributeValue(elt, "hx-confirm"); if (confirmQuestion) { if(!confirm(confirmQuestion)) return endRequestLock(); } @@ -1135,7 +1135,7 @@ var kutty = kutty || (function () { target:target, verb:verb }; - if(!triggerEvent(elt, 'configRequest.kutty', requestConfig)) return endRequestLock(); + if(!triggerEvent(elt, 'configRequest.htmx', requestConfig)) return endRequestLock(); // request type var requestURL; @@ -1160,10 +1160,10 @@ var kutty = kutty || (function () { var eventDetail = {xhr: xhr, target: target}; xhr.onload = function () { try { - if (!triggerEvent(elt, 'beforeOnLoad.kutty', eventDetail)) return; + if (!triggerEvent(elt, 'beforeOnLoad.htmx', eventDetail)) return; - handleTrigger(elt, this.getResponseHeader("X-KT-Trigger")); - var pushedUrl = this.getResponseHeader("X-KT-Push"); + handleTrigger(elt, this.getResponseHeader("X-HX-Trigger")); + var pushedUrl = this.getResponseHeader("X-HX-Push"); var shouldSaveHistory = shouldPush(elt) || pushedUrl; @@ -1173,7 +1173,7 @@ var kutty = kutty || (function () { } // don't process 'No Content' response if (this.status !== 204) { - if (!triggerEvent(elt, 'beforeSwap.kutty', eventDetail)) return; + if (!triggerEvent(elt, 'beforeSwap.htmx', eventDetail)) return; var resp = this.response; @@ -1184,24 +1184,24 @@ var kutty = kutty || (function () { var swapSpec = getSwapSpecification(elt); - target.classList.add("kutty-swapping"); + target.classList.add("htmx-swapping"); var doSwap = function () { try { var settleTasks = swapResponse(swapSpec.swapStyle, target, elt, resp); - target.classList.remove("kutty-swapping"); - target.classList.add("kutty-settling"); - triggerEvent(elt, 'afterSwap.kutty', eventDetail); + target.classList.remove("htmx-swapping"); + target.classList.add("htmx-settling"); + triggerEvent(elt, 'afterSwap.htmx', eventDetail); var doSettle = function(){ forEach(settleTasks, function (settleTask) { settleTask.call(); }); - target.classList.remove("kutty-settling"); + target.classList.remove("htmx-settling"); // push URL and save new page if (shouldSaveHistory) { pushUrlIntoHistory(pushedUrl || requestURL ); } - triggerEvent(elt, 'afterSettle.kutty', eventDetail); + triggerEvent(elt, 'afterSettle.htmx', eventDetail); } if (swapSpec.settleDelay > 0) { @@ -1210,7 +1210,7 @@ var kutty = kutty || (function () { doSettle(); } } catch (e) { - triggerErrorEvent(elt, 'swapError.kutty', eventDetail); + triggerErrorEvent(elt, 'swapError.htmx', eventDetail); throw e; } }; @@ -1222,24 +1222,24 @@ var kutty = kutty || (function () { } } } else { - triggerErrorEvent(elt, 'responseError.kutty', eventDetail); + triggerErrorEvent(elt, 'responseError.htmx', eventDetail); } } catch (e) { eventDetail['exception'] = e; - triggerErrorEvent(elt, 'onLoadError.kutty', eventDetail); + triggerErrorEvent(elt, 'onLoadError.htmx', eventDetail); throw e; } finally { removeRequestIndicatorClasses(elt); endRequestLock(); - triggerEvent(elt, 'afterOnLoad.kutty', eventDetail); + triggerEvent(elt, 'afterOnLoad.htmx', eventDetail); } } xhr.onerror = function () { removeRequestIndicatorClasses(elt); - triggerErrorEvent(elt, 'sendError.kutty', eventDetail); + triggerErrorEvent(elt, 'sendError.htmx', eventDetail); endRequestLock(); } - if(!triggerEvent(elt, 'beforeRequest.kutty', eventDetail)) return endRequestLock(); + if(!triggerEvent(elt, 'beforeRequest.htmx', eventDetail)) return endRequestLock(); addRequestIndicatorClasses(elt); xhr.send(verb === 'get' ? null : urlEncode(filteredParameters)); } @@ -1256,21 +1256,21 @@ var kutty = kutty || (function () { } } - // insert kutty-indicator css rules immediate, if not configured otherwise + // insert htmx-indicator css rules immediate, if not configured otherwise (function() { var metaConfig = getMetaConfig(); if (metaConfig === null || metaConfig.includeIndicatorStyles !== false) { getDocument().head.insertAdjacentHTML("beforeend", "<style>\ - .kutty-indicator{opacity:0;transition: opacity 200ms ease-in;}\ - .kutty-request .kutty-indicator{opacity:1}\ - .kutty-request.kutty-indicator{opacity:1}\ + .htmx-indicator{opacity:0;transition: opacity 200ms ease-in;}\ + .htmx-request .htmx-indicator{opacity:1}\ + .htmx-request.htmx-indicator{opacity:1}\ </style>"); } })(); function getMetaConfig() { - var element = getDocument().querySelector('meta[name="kutty-config"]'); + var element = getDocument().querySelector('meta[name="htmx-config"]'); if (element) { return JSON.parse(element.content); } else { @@ -1281,7 +1281,7 @@ var kutty = kutty || (function () { function mergeMetaConfig() { var metaConfig = getMetaConfig(); if (metaConfig) { - kutty.config = mergeObjects(kutty.config , metaConfig) + htmx.config = mergeObjects(htmx.config , metaConfig) } } @@ -1290,7 +1290,7 @@ var kutty = kutty || (function () { mergeMetaConfig(); var body = getDocument().body; processNode(body); - triggerEvent(body, 'load.kutty', {}); + triggerEvent(body, 'load.htmx', {}); window.onpopstate = function () { restoreHistory(); }; diff --git a/test/attributes/kt-boost.js b/test/attributes/hx-boost.js index 86ea2c34..41dfb29e 100644 --- a/test/attributes/kt-boost.js +++ b/test/attributes/hx-boost.js @@ -1,4 +1,4 @@ -describe("kt-boost attribute", function() { +describe("hx-boost attribute", function() { beforeEach(function () { this.server = makeServer(); @@ -11,7 +11,7 @@ describe("kt-boost attribute", function() { it('handles basic anchor properly', function () { this.server.respondWith("GET", "/test", "Boosted"); - var div = make('<div kt-target="this" kt-boost="true"><a id="a1" href="/test">Foo</a></div>'); + var div = make('<div hx-target="this" hx-boost="true"><a id="a1" href="/test">Foo</a></div>'); var a = byId('a1'); a.click(); this.server.respond(); @@ -22,7 +22,7 @@ describe("kt-boost attribute", function() { it('handles basic form post properly', function () { this.server.respondWith("POST", "/test", "Boosted"); this.server.respondWith("POST", "/test", "Boosted"); - var div = make('<div kt-target="this" kt-boost="true"><form id="f1" action="/test" method="post"><button id="b1">Submit</button></form></div>'); + var div = make('<div hx-target="this" hx-boost="true"><form id="f1" action="/test" method="post"><button id="b1">Submit</button></form></div>'); var btn = byId('b1'); btn.click(); this.server.respond(); @@ -31,7 +31,7 @@ describe("kt-boost attribute", function() { it('handles basic form get properly', function () { this.server.respondWith("GET", "/test", "Boosted"); - var div = make('<div kt-target="this" kt-boost="true"><form id="f1" action="/test" method="get"><button id="b1">Submit</button></form></div>'); + var div = make('<div hx-target="this" hx-boost="true"><form id="f1" action="/test" method="get"><button id="b1">Submit</button></form></div>'); var btn = byId('b1'); btn.click(); this.server.respond(); @@ -40,7 +40,7 @@ describe("kt-boost attribute", function() { it('handles basic form with no explicit method property', function () { this.server.respondWith("GET", "/test", "Boosted"); - var div = make('<div kt-target="this" kt-boost="true"><form id="f1" action="/test"><button id="b1">Submit</button></form></div>'); + var div = make('<div hx-target="this" hx-boost="true"><form id="f1" action="/test"><button id="b1">Submit</button></form></div>'); var btn = byId('b1'); btn.click(); this.server.respond(); diff --git a/test/attributes/kt-classes.js b/test/attributes/hx-classes.js index 3ad68cc2..a138976e 100644 --- a/test/attributes/kt-classes.js +++ b/test/attributes/hx-classes.js @@ -1,4 +1,4 @@ -describe("kt-classes attribute", function(){ +describe("hx-classes attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -10,7 +10,7 @@ describe("kt-classes attribute", function(){ it('adds classes properly', function(done) { - var div = make('<div kt-classes="add c1">Click Me!</div>') + var div = make('<div hx-classes="add c1">Click Me!</div>') should.equal(div.classList.length, 0); setTimeout(function(){ should.equal(div.classList.contains("c1"), true); @@ -20,7 +20,7 @@ describe("kt-classes attribute", function(){ it('removes classes properly', function(done) { - var div = make('<div class="foo bar" kt-classes="remove bar">Click Me!</div>') + var div = make('<div class="foo bar" hx-classes="remove bar">Click Me!</div>') should.equal(div.classList.contains("foo"), true); should.equal(div.classList.contains("bar"), true); setTimeout(function(){ diff --git a/test/attributes/kt-delete.js b/test/attributes/hx-delete.js index e4789e34..42892e31 100644 --- a/test/attributes/kt-delete.js +++ b/test/attributes/hx-delete.js @@ -1,4 +1,4 @@ -describe("kt-delete attribute", function(){ +describe("hx-delete attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -15,7 +15,7 @@ describe("kt-delete attribute", function(){ xhr.respond(200, {}, "Deleted!"); }); - var btn = make('<button kt-delete="/test">Click Me!</button>') + var btn = make('<button hx-delete="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Deleted!"); diff --git a/test/attributes/kt-error-url.js b/test/attributes/hx-error-url.js index 4a573ef1..1984edcc 100644 --- a/test/attributes/kt-error-url.js +++ b/test/attributes/hx-error-url.js @@ -1,4 +1,4 @@ -describe("kt-error-url attribute", function(){ +describe("hx-error-url attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -13,7 +13,7 @@ describe("kt-error-url attribute", function(){ this.server.respondWith("POST", "/error", function(xhr){ should.equal(JSON.parse(xhr.requestBody).detail.xhr.status, 404); }); - var btn = make('<button kt-error-url="/error" kt-get="/bad">Click Me!</button>') + var btn = make('<button hx-error-url="/error" hx-get="/bad">Click Me!</button>') btn.click(); this.server.respond(); this.server.respond(); diff --git a/test/attributes/kt-get.js b/test/attributes/hx-get.js index b5f79263..3a36da20 100644 --- a/test/attributes/kt-get.js +++ b/test/attributes/hx-get.js @@ -1,4 +1,4 @@ -describe("kt-get attribute", function() { +describe("hx-get attribute", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -11,7 +11,7 @@ describe("kt-get attribute", function() { it('issues a GET request on click and swaps content', function () { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-get="/test">Click Me!</button>') + var btn = make('<button hx-get="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Clicked!"); @@ -21,7 +21,7 @@ describe("kt-get attribute", function() { this.server.respondWith("GET", "/test", function (xhr) { xhr.respond(200, {}, "Clicked!"); }); - make('<form><input name="i1" value="value"/><button id="b1" kt-get="/test">Click Me!</inputbutton></form>') + make('<form><input name="i1" value="value"/><button id="b1" hx-get="/test">Click Me!</inputbutton></form>') var btn = byId("b1"); btn.click(); this.server.respond(); diff --git a/test/attributes/kt-include.js b/test/attributes/hx-include.js index e92eb9d7..a263076e 100644 --- a/test/attributes/kt-include.js +++ b/test/attributes/hx-include.js @@ -1,4 +1,4 @@ -describe("kt-include attribute", function() { +describe("hx-include attribute", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -14,7 +14,7 @@ describe("kt-include attribute", function() { params['i1'].should.equal("test"); xhr.respond(200, {}, "Clicked!") }); - var div = make('<div kt-target="this"><input kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/></div>') + var div = make('<div hx-target="this"><input hx-post="/include" hx-trigger="click" id="i1" name="i1" value="test"/></div>') var input = byId("i1") input.click(); this.server.respond(); @@ -27,7 +27,7 @@ describe("kt-include attribute", function() { params['i1'].should.equal("test"); xhr.respond(200, {}, "Clicked!") }); - var div = make('<form kt-target="this"><div id="d1" kt-post="/include"></div><input name="i1" value="test"/></form>') + var div = make('<form hx-target="this"><div id="d1" hx-post="/include"></div><input name="i1" value="test"/></form>') var input = byId("d1") input.click(); this.server.respond(); @@ -40,7 +40,7 @@ describe("kt-include attribute", function() { should.equal(params['i1'], undefined); xhr.respond(200, {}, "Clicked!") }); - var div = make('<form kt-target="this"><div id="d1" kt-get="/include"></div><input name="i1" value="test"/></form>') + var div = make('<form hx-target="this"><div id="d1" hx-get="/include"></div><input name="i1" value="test"/></form>') var input = byId("d1") input.click(); this.server.respond(); @@ -53,7 +53,7 @@ describe("kt-include attribute", function() { params['i1'].should.equal("test"); xhr.respond(200, {}, "Clicked!") }); - var div = make('<form kt-target="this"><input kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/></form>') + var div = make('<form hx-target="this"><input hx-post="/include" hx-trigger="click" id="i1" name="i1" value="test"/></form>') var input = byId("i1") input.click(); this.server.respond(); @@ -66,8 +66,8 @@ describe("kt-include attribute", function() { params['i1'].should.deep.equal(["test", "test2"]); xhr.respond(200, {}, "Clicked!") }); - var div = make('<form kt-target="this">' + - '<input kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/>' + + var div = make('<form hx-target="this">' + + '<input hx-post="/include" hx-trigger="click" id="i1" name="i1" value="test"/>' + '<input name="i1" value="test2"/>' + '</form>') var input = byId("i1") @@ -82,8 +82,8 @@ describe("kt-include attribute", function() { params['i1'].should.equal("test"); xhr.respond(200, {}, "Clicked!") }); - var div = make('<form id="f1" kt-target="this">' + - '<input kt-include="#f1" kt-post="/include" kt-trigger="click" id="i1" name="i1" value="test"/>' + + var div = make('<form id="f1" hx-target="this">' + + '<input hx-include="#f1" hx-post="/include" hx-trigger="click" id="i1" name="i1" value="test"/>' + '</form>') var input = byId("i1") input.click(); @@ -98,7 +98,7 @@ describe("kt-include attribute", function() { xhr.respond(200, {}, "Clicked!") }); make('<input id="i1" name="i1" value="test"/>'); - var div = make('<div kt-post="/include" kt-include="#i1"></div>') + var div = make('<div hx-post="/include" hx-include="#i1"></div>') div.click(); this.server.respond(); div.innerHTML.should.equal("Clicked!"); @@ -113,7 +113,7 @@ describe("kt-include attribute", function() { }); make('<input id="i1" name="i1" value="test"/>'); make('<input id="i2" name="i2" value="test"/>'); - var div = make('<div kt-post="/include" kt-include="#i1, #i2"></div>') + var div = make('<div hx-post="/include" hx-include="#i1, #i2"></div>') div.click(); this.server.respond(); div.innerHTML.should.equal("Clicked!"); @@ -130,7 +130,7 @@ describe("kt-include attribute", function() { '<input name="i1" value="test"/>' + '<input name="i2" value="test"/>' + '</form> '); - var div = make('<div kt-post="/include" kt-include="#f1"></div>') + var div = make('<div hx-post="/include" hx-include="#f1"></div>') div.click(); this.server.respond(); div.innerHTML.should.equal("Clicked!"); diff --git a/test/attributes/kt-indicator.js b/test/attributes/hx-indicator.js index d42c939b..7b1503bf 100644 --- a/test/attributes/kt-indicator.js +++ b/test/attributes/hx-indicator.js @@ -1,4 +1,4 @@ -describe("kt-indicator attribute", function(){ +describe("hx-indicator attribute", function(){ beforeEach(function() { this.server = sinon.fakeServer.create(); clearWorkArea(); @@ -11,26 +11,26 @@ describe("kt-indicator attribute", function(){ it('Indicator classes are properly put on element with no explicit indicator', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-get="/test">Click Me!</button>') + var btn = make('<button hx-get="/test">Click Me!</button>') btn.click(); - btn.classList.contains("kutty-request").should.equal(true); + btn.classList.contains("htmx-request").should.equal(true); this.server.respond(); - btn.classList.contains("kutty-request").should.equal(false); + btn.classList.contains("htmx-request").should.equal(false); }); it('Indicator classes are properly put on element with explicit indicator', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-get="/test" kt-indicator="#a1, #a2">Click Me!</button>') + var btn = make('<button hx-get="/test" hx-indicator="#a1, #a2">Click Me!</button>') var a1 = make('<a id="a1"></a>') var a2 = make('<a id="a2"></a>') btn.click(); - btn.classList.contains("kutty-request").should.equal(false); - a1.classList.contains("kutty-request").should.equal(true); - a2.classList.contains("kutty-request").should.equal(true); + btn.classList.contains("htmx-request").should.equal(false); + a1.classList.contains("htmx-request").should.equal(true); + a2.classList.contains("htmx-request").should.equal(true); this.server.respond(); - btn.classList.contains("kutty-request").should.equal(false); - a1.classList.contains("kutty-request").should.equal(false); - a2.classList.contains("kutty-request").should.equal(false); + btn.classList.contains("htmx-request").should.equal(false); + a1.classList.contains("htmx-request").should.equal(false); + a2.classList.contains("htmx-request").should.equal(false); }); }) diff --git a/test/attributes/kt-params.js b/test/attributes/hx-params.js index 4e57930f..49c9d54f 100644 --- a/test/attributes/kt-params.js +++ b/test/attributes/hx-params.js @@ -1,4 +1,4 @@ -describe("kt-params attribute", function() { +describe("hx-params attribute", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -16,7 +16,7 @@ describe("kt-params attribute", function() { should.equal(params['i3'], undefined); xhr.respond(200, {}, "Clicked!") }); - var form = make('<form kt-trigger="click" kt-post="/params" kt-params="none">' + + var form = make('<form hx-trigger="click" hx-post="/params" hx-params="none">' + '<input name="i1" value="test"/>' + '<input name="i2" value="test"/>' + '<input name="i3" value="test"/>' + @@ -34,7 +34,7 @@ describe("kt-params attribute", function() { should.equal(params['i3'], "test"); xhr.respond(200, {}, "Clicked!") }); - var form = make('<form kt-trigger="click" kt-post="/params" kt-params="*">' + + var form = make('<form hx-trigger="click" hx-post="/params" hx-params="*">' + '<input name="i1" value="test"/>' + '<input name="i2" value="test"/>' + '<input name="i3" value="test"/>' + @@ -52,7 +52,7 @@ describe("kt-params attribute", function() { should.equal(params['i3'], "test"); xhr.respond(200, {}, "Clicked!") }); - var form = make('<form kt-trigger="click" kt-post="/params" kt-params="i1, i3">' + + var form = make('<form hx-trigger="click" hx-post="/params" hx-params="i1, i3">' + '<input name="i1" value="test"/>' + '<input name="i2" value="test"/>' + '<input name="i3" value="test"/>' + @@ -70,7 +70,7 @@ describe("kt-params attribute", function() { should.equal(params['i3'], undefined); xhr.respond(200, {}, "Clicked!") }); - var form = make('<form kt-trigger="click" kt-post="/params" kt-params="not i1, i3">' + + var form = make('<form hx-trigger="click" hx-post="/params" hx-params="not i1, i3">' + '<input name="i1" value="test"/>' + '<input name="i2" value="test"/>' + '<input name="i3" value="test"/>' + diff --git a/test/attributes/kt-patch.js b/test/attributes/hx-patch.js index f6e19c05..5f4abd63 100644 --- a/test/attributes/kt-patch.js +++ b/test/attributes/hx-patch.js @@ -1,4 +1,4 @@ -describe("kt-patch attribute", function(){ +describe("hx-patch attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -15,7 +15,7 @@ describe("kt-patch attribute", function(){ xhr.respond(200, {}, "Patched!"); }); - var btn = make('<button kt-patch="/test">Click Me!</button>') + var btn = make('<button hx-patch="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Patched!"); diff --git a/test/attributes/kt-post.js b/test/attributes/hx-post.js index d8eb718a..4b548018 100644 --- a/test/attributes/kt-post.js +++ b/test/attributes/hx-post.js @@ -1,4 +1,4 @@ -describe("kt-post attribute", function(){ +describe("hx-post attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -15,7 +15,7 @@ describe("kt-post attribute", function(){ xhr.respond(200, {}, "Posted!"); }); - var btn = make('<button kt-post="/test">Click Me!</button>') + var btn = make('<button hx-post="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Posted!"); diff --git a/test/attributes/kt-push-url.js b/test/attributes/hx-push-url.js index a5fa2368..c76d6aa4 100644 --- a/test/attributes/kt-push-url.js +++ b/test/attributes/hx-push-url.js @@ -1,6 +1,6 @@ -describe("kt-push-url attribute", function() { +describe("hx-push-url attribute", function() { - var KUTTY_HISTORY_CACHE = "kutty-history-cache"; + var KUTTY_HISTORY_CACHE = "htmx-history-cache"; beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -15,7 +15,7 @@ describe("kt-push-url attribute", function() { it("navigation should push an element into the cache ", function () { this.server.respondWith("GET", "/test", "second"); getWorkArea().innerHTML.should.be.equal(""); - var div = make('<div kt-push-url="true" kt-get="/test">first</div>'); + var div = make('<div hx-push-url="true" hx-get="/test">first</div>'); div.click(); this.server.respond(); getWorkArea().textContent.should.equal("second") @@ -24,10 +24,10 @@ describe("kt-push-url attribute", function() { }); it("restore should return old value", function () { - this.server.respondWith("GET", "/test1", '<div id="d2" kt-push-url="true" kt-get="/test2" kt-swap="outerHTML settle:0">test1</div>'); - this.server.respondWith("GET", "/test2", '<div id="d3" kt-push-url="true" kt-get="/test3" kt-swap="outerHTML settle:0">test2</div>'); + this.server.respondWith("GET", "/test1", '<div id="d2" hx-push-url="true" hx-get="/test2" hx-swap="outerHTML settle:0">test1</div>'); + this.server.respondWith("GET", "/test2", '<div id="d3" hx-push-url="true" hx-get="/test3" hx-swap="outerHTML settle:0">test2</div>'); - make('<div id="d1" kt-push-url="true" kt-get="/test1" kt-swap="outerHTML settle:0">init</div>'); + make('<div id="d1" hx-push-url="true" hx-get="/test1" hx-swap="outerHTML settle:0">init</div>'); byId("d1").click(); this.server.respond(); @@ -41,7 +41,7 @@ describe("kt-push-url attribute", function() { var cache = JSON.parse(localStorage.getItem(KUTTY_HISTORY_CACHE)); cache.length.should.equal(2); - kutty._('restoreHistory')("/test1") + htmx._('restoreHistory')("/test1") this.server.respond(); getWorkArea().textContent.should.equal("test1") }); @@ -50,10 +50,10 @@ describe("kt-push-url attribute", function() { var x = 0; this.server.respondWith("GET", /test.*/, function(xhr){ x++; - xhr.respond(200, {}, '<div id="d1" kt-push-url="true" kt-get="/test' + x + '" kt-swap="outerHTML settle:0"></div>') + xhr.respond(200, {}, '<div id="d1" hx-push-url="true" hx-get="/test' + x + '" hx-swap="outerHTML settle:0"></div>') }); getWorkArea().innerHTML.should.be.equal(""); - make('<div id="d1" kt-push-url="true" kt-get="/test" kt-swap="outerHTML settle:0"></div>'); + make('<div id="d1" hx-push-url="true" hx-get="/test" hx-swap="outerHTML settle:0"></div>'); for (var i = 0; i < 20; i++) { // issue 20 requests byId("d1").click(); this.server.respond(); @@ -63,10 +63,10 @@ describe("kt-push-url attribute", function() { }); it("cache miss should issue another GET", function () { - this.server.respondWith("GET", "/test1", '<div id="d2" kt-push-url="true" kt-get="/test2" kt-swap="outerHTML settle:0">test1</div>'); - this.server.respondWith("GET", "/test2", '<div id="d3" kt-push-url="true" kt-get="/test3" kt-swap="outerHTML settle:0">test2</div>'); + this.server.respondWith("GET", "/test1", '<div id="d2" hx-push-url="true" hx-get="/test2" hx-swap="outerHTML settle:0">test1</div>'); + this.server.respondWith("GET", "/test2", '<div id="d3" hx-push-url="true" hx-get="/test3" hx-swap="outerHTML settle:0">test2</div>'); - make('<div id="d1" kt-push-url="true" kt-get="/test1" kt-swap="outerHTML settle:0">init</div>'); + make('<div id="d1" hx-push-url="true" hx-get="/test1" hx-swap="outerHTML settle:0">init</div>'); byId("d1").click(); this.server.respond(); @@ -81,7 +81,7 @@ describe("kt-push-url attribute", function() { cache.length.should.equal(2); localStorage.removeItem(KUTTY_HISTORY_CACHE); // clear cache - kutty._('restoreHistory')("/test1") + htmx._('restoreHistory')("/test1") this.server.respond(); getWorkArea().textContent.should.equal("test1") }); diff --git a/test/attributes/kt-put.js b/test/attributes/hx-put.js index 957a1522..ad347da6 100644 --- a/test/attributes/kt-put.js +++ b/test/attributes/hx-put.js @@ -1,4 +1,4 @@ -describe("kt-put attribute", function(){ +describe("hx-put attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -15,7 +15,7 @@ describe("kt-put attribute", function(){ xhr.respond(200, {}, "Putted!"); }); - var btn = make('<button kt-put="/test">Click Me!</button>') + var btn = make('<button hx-put="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Putted!"); diff --git a/test/attributes/kt-select.js b/test/attributes/hx-select.js index 23d84ea4..916571c1 100644 --- a/test/attributes/kt-select.js +++ b/test/attributes/hx-select.js @@ -1,4 +1,4 @@ -describe("BOOTSTRAP - kutty AJAX Tests", function(){ +describe("BOOTSTRAP - htmx AJAX Tests", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -12,7 +12,7 @@ describe("BOOTSTRAP - kutty AJAX Tests", function(){ { var i = 1; this.server.respondWith("GET", "/test", "<div id='d1'>foo</div><div id='d2'>bar</div>"); - var div = make('<div kt-get="/test" kt-select="#d1"></div>'); + var div = make('<div hx-get="/test" hx-select="#d1"></div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("<div id=\"d1\">foo</div>"); @@ -22,7 +22,7 @@ describe("BOOTSTRAP - kutty AJAX Tests", function(){ { var i = 1; this.server.respondWith("GET", "/test", "<html><body><div id='d1'>foo</div><div id='d2'>bar</div></body></html>"); - var div = make('<div kt-get="/test" kt-select="#d1"></div>'); + var div = make('<div hx-get="/test" hx-select="#d1"></div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("<div id=\"d1\">foo</div>"); diff --git a/test/attributes/kt-swap-oob.js b/test/attributes/hx-swap-oob.js index 7985b19b..b6b2afb8 100644 --- a/test/attributes/kt-swap-oob.js +++ b/test/attributes/hx-swap-oob.js @@ -1,4 +1,4 @@ -describe("kt-swap-oob attribute", function () { +describe("hx-swap-oob attribute", function () { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -9,8 +9,8 @@ describe("kt-swap-oob attribute", function () { }); it('handles basic response properly', function () { - this.server.respondWith("GET", "/test", "Clicked<div id='d1' kt-swap-oob='true'>Swapped</div>"); - var div = make('<div kt-get="/test">click me</div>'); + this.server.respondWith("GET", "/test", "Clicked<div id='d1' hx-swap-oob='true'>Swapped</div>"); + var div = make('<div hx-get="/test">click me</div>'); make('<div id="d1"></div>'); div.click(); this.server.respond(); @@ -19,8 +19,8 @@ describe("kt-swap-oob attribute", function () { }) it('handles more than one oob swap properly', function () { - this.server.respondWith("GET", "/test", "Clicked<div id='d1' kt-swap-oob='true'>Swapped1</div><div id='d2' kt-swap-oob='true'>Swapped2</div>"); - var div = make('<div kt-get="/test">click me</div>'); + this.server.respondWith("GET", "/test", "Clicked<div id='d1' hx-swap-oob='true'>Swapped1</div><div id='d2' hx-swap-oob='true'>Swapped2</div>"); + var div = make('<div hx-get="/test">click me</div>'); make('<div id="d1"></div>'); make('<div id="d2"></div>'); div.click(); @@ -31,8 +31,8 @@ describe("kt-swap-oob attribute", function () { }) it('handles no id match properly', function () { - this.server.respondWith("GET", "/test", "Clicked<div id='d1' kt-swap-oob='true'>Swapped</div>"); - var div = make('<div kt-get="/test">click me</div>'); + this.server.respondWith("GET", "/test", "Clicked<div id='d1' hx-swap-oob='true'>Swapped</div>"); + var div = make('<div hx-get="/test">click me</div>'); div.click(); this.server.respond(); div.innerText.should.equal("Clicked"); diff --git a/test/attributes/kt-swap.js b/test/attributes/hx-swap.js index 1d99bef8..ee5307ec 100644 --- a/test/attributes/kt-swap.js +++ b/test/attributes/hx-swap.js @@ -1,4 +1,4 @@ -describe("kt-swap attribute", function(){ +describe("hx-swap attribute", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -10,13 +10,13 @@ describe("kt-swap attribute", function(){ it('swap innerHTML properly', function() { - this.server.respondWith("GET", "/test", '<a kt-get="/test2">Click Me</a>'); + this.server.respondWith("GET", "/test", '<a hx-get="/test2">Click Me</a>'); this.server.respondWith("GET", "/test2", "Clicked!"); - var div = make('<div kt-get="/test"></div>') + var div = make('<div hx-get="/test"></div>') div.click(); this.server.respond(); - div.innerHTML.should.equal('<a kt-get="/test2">Click Me</a>'); + div.innerHTML.should.equal('<a hx-get="/test2">Click Me</a>'); var a = div.querySelector('a'); a.click(); this.server.respond(); @@ -25,10 +25,10 @@ describe("kt-swap attribute", function(){ it('swap outerHTML properly', function() { - this.server.respondWith("GET", "/test", '<a id="a1" kt-get="/test2">Click Me</a>'); + this.server.respondWith("GET", "/test", '<a id="a1" hx-get="/test2">Click Me</a>'); this.server.respondWith("GET", "/test2", "Clicked!"); - var div = make('<div id="d1" kt-get="/test" kt-swap="outerHTML"></div>') + var div = make('<div id="d1" hx-get="/test" hx-swap="outerHTML"></div>') div.click(); should.equal(byId("d1"), div); this.server.respond(); @@ -43,11 +43,11 @@ describe("kt-swap attribute", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="beforebegin">*</div>') + var div = make('<div hx-get="/test" hx-swap="beforebegin">*</div>') var parent = div.parentElement; div.click(); this.server.respond(); @@ -73,11 +73,11 @@ describe("kt-swap attribute", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="afterbegin">*</div>') + var div = make('<div hx-get="/test" hx-swap="afterbegin">*</div>') div.click(); this.server.respond(); div.innerText.should.equal("1*"); @@ -100,11 +100,11 @@ describe("kt-swap attribute", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="afterbegin"></div>') + var div = make('<div hx-get="/test" hx-swap="afterbegin"></div>') div.click(); this.server.respond(); div.innerText.should.equal("1"); @@ -127,11 +127,11 @@ describe("kt-swap attribute", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="afterend">*</div>') + var div = make('<div hx-get="/test" hx-swap="afterend">*</div>') var parent = div.parentElement; div.click(); this.server.respond(); @@ -157,11 +157,11 @@ describe("kt-swap attribute", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="beforeend">*</div>') + var div = make('<div hx-get="/test" hx-swap="beforeend">*</div>') div.click(); this.server.respond(); div.innerText.should.equal("*1"); @@ -184,11 +184,11 @@ describe("kt-swap attribute", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="beforeend"></div>') + var div = make('<div hx-get="/test" hx-swap="beforeend"></div>') div.click(); this.server.respond(); div.innerText.should.equal("1"); @@ -207,24 +207,24 @@ describe("kt-swap attribute", function(){ }); it('properly parses various swap specifications', function(){ - var swapSpec = kutty._("getSwapSpecification"); // internal function for swap spec + var swapSpec = htmx._("getSwapSpecification"); // internal function for swap spec swapSpec(make("<div/>")).swapStyle.should.equal("innerHTML") - swapSpec(make("<div kt-swap='innerHTML'/>")).swapStyle.should.equal("innerHTML") - swapSpec(make("<div kt-swap='innerHTML'/>")).swapDelay.should.equal(0) - swapSpec(make("<div kt-swap='innerHTML'/>")).settleDelay.should.equal(100) - swapSpec(make("<div kt-swap='innerHTML swap:10'/>")).swapDelay.should.equal(10) - swapSpec(make("<div kt-swap='innerHTML settle:10'/>")).settleDelay.should.equal(10) - swapSpec(make("<div kt-swap='innerHTML swap:10 settle:11'/>")).swapDelay.should.equal(10) - swapSpec(make("<div kt-swap='innerHTML swap:10 settle:11'/>")).settleDelay.should.equal(11) - swapSpec(make("<div kt-swap='innerHTML settle:11 swap:10'/>")).swapDelay.should.equal(10) - swapSpec(make("<div kt-swap='innerHTML settle:11 swap:10'/>")).settleDelay.should.equal(11) - swapSpec(make("<div kt-swap='innerHTML nonsense settle:11 swap:10'/>")).settleDelay.should.equal(11) - swapSpec(make("<div kt-swap='innerHTML nonsense settle:11 swap:10 '/>")).settleDelay.should.equal(11) + 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'/>")).settleDelay.should.equal(100) + 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 swap:10 settle:11'/>")).swapDelay.should.equal(10) + swapSpec(make("<div hx-swap='innerHTML swap:10 settle:11'/>")).settleDelay.should.equal(11) + swapSpec(make("<div hx-swap='innerHTML settle:11 swap:10'/>")).swapDelay.should.equal(10) + swapSpec(make("<div hx-swap='innerHTML settle:11 swap:10'/>")).settleDelay.should.equal(11) + swapSpec(make("<div hx-swap='innerHTML nonsense settle:11 swap:10'/>")).settleDelay.should.equal(11) + swapSpec(make("<div hx-swap='innerHTML nonsense settle:11 swap:10 '/>")).settleDelay.should.equal(11) }) it('works with a swap delay', function(done) { this.server.respondWith("GET", "/test", "Clicked!"); - var div = make("<div kt-get='/test' kt-swap='innerHTML swap:10ms'></div>"); + var div = make("<div hx-get='/test' hx-swap='innerHTML swap:10ms'></div>"); div.click(); this.server.respond(); div.innerText.should.equal(""); @@ -235,8 +235,8 @@ describe("kt-swap attribute", function(){ }); it('works with a settle delay', function(done) { - this.server.respondWith("GET", "/test", "<div id='d1' class='foo' kt-get='/test' kt-swap='outerHTML settle:10ms'></div>"); - var div = make("<div id='d1' kt-get='/test' kt-swap='outerHTML settle:10ms'></div>"); + this.server.respondWith("GET", "/test", "<div id='d1' class='foo' hx-get='/test' hx-swap='outerHTML settle:10ms'></div>"); + var div = make("<div id='d1' hx-get='/test' hx-swap='outerHTML settle:10ms'></div>"); div.click(); this.server.respond(); div.classList.contains('foo').should.equal(false); diff --git a/test/attributes/kt-target.js b/test/attributes/hx-target.js index f9c15f0e..c28fcc9d 100644 --- a/test/attributes/kt-target.js +++ b/test/attributes/hx-target.js @@ -1,4 +1,4 @@ -describe("kt-target attribute", function(){ +describe("hx-target attribute", function(){ beforeEach(function() { this.server = sinon.fakeServer.create(); clearWorkArea(); @@ -11,7 +11,7 @@ describe("kt-target attribute", function(){ it('targets an adjacent element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-target="#d1" kt-get="/test">Click Me!</button>') + var btn = make('<button hx-target="#d1" hx-get="/test">Click Me!</button>') var div1 = make('<div id="d1"></div>') btn.click(); this.server.respond(); @@ -21,7 +21,7 @@ describe("kt-target attribute", function(){ it('targets a parent element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var div1 = make('<div id="d1"><button id="b1" kt-target="#d1" kt-get="/test">Click Me!</button></div>') + var div1 = make('<div id="d1"><button id="b1" hx-target="#d1" hx-get="/test">Click Me!</button></div>') var btn = byId("b1") btn.click(); this.server.respond(); @@ -31,7 +31,7 @@ describe("kt-target attribute", function(){ it('targets a `this` element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var div1 = make('<div kt-target="this"><button id="b1" kt-get="/test">Click Me!</button></div>') + var div1 = make('<div hx-target="this"><button id="b1" hx-get="/test">Click Me!</button></div>') var btn = byId("b1") btn.click(); this.server.respond(); @@ -41,7 +41,7 @@ describe("kt-target attribute", function(){ it('targets a `closest` element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var div1 = make('<div><p><i><button id="b1" kt-target="closest div" kt-get="/test">Click Me!</button></i></p></div>') + var div1 = make('<div><p><i><button id="b1" hx-target="closest div" hx-get="/test">Click Me!</button></i></p></div>') var btn = byId("b1") btn.click(); this.server.respond(); @@ -51,7 +51,7 @@ describe("kt-target attribute", function(){ it('targets an inner element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-target="#d1" kt-get="/test">Click Me!<div id="d1"></div></button>') + var btn = make('<button hx-target="#d1" hx-get="/test">Click Me!<div id="d1"></div></button>') var div1 = byId("d1") btn.click(); this.server.respond(); @@ -62,7 +62,7 @@ describe("kt-target attribute", function(){ it('handles bad target gracefully', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-target="bad" kt-get="/test">Click Me!</button>') + var btn = make('<button hx-target="bad" hx-get="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Click Me!"); diff --git a/test/attributes/kt-trigger.js b/test/attributes/hx-trigger.js index a8cbced2..62052500 100644 --- a/test/attributes/kt-trigger.js +++ b/test/attributes/hx-trigger.js @@ -1,4 +1,4 @@ -describe("kt-trigger attribute", function(){ +describe("hx-trigger attribute", function(){ beforeEach(function() { this.server = sinon.fakeServer.create(); clearWorkArea(); @@ -12,7 +12,7 @@ describe("kt-trigger attribute", function(){ { this.server.respondWith("GET", "/test", "Clicked!"); - var form = make('<form kt-get="/test" kt-trigger="click">Click Me!</form>'); + var form = make('<form hx-get="/test" hx-trigger="click">Click Me!</form>'); form.click(); form.innerHTML.should.equal("Click Me!"); this.server.respond(); @@ -26,7 +26,7 @@ describe("kt-trigger attribute", function(){ requests++; xhr.respond(200, {}, "Requests: " + requests); }); - var input = make('<input kt-trigger="click changed" kt-target="#d1" kt-get="/test" value="foo"/>'); + var input = make('<input hx-trigger="click changed" hx-target="#d1" hx-get="/test" value="foo"/>'); var div = make('<div id="d1"></div>'); input.click(); this.server.respond(); @@ -50,7 +50,7 @@ describe("kt-trigger attribute", function(){ requests++; xhr.respond(200, {}, "Requests: " + requests); }); - var input = make('<input kt-trigger="click once" kt-target="#d1" kt-get="/test" value="foo"/>'); + var input = make('<input hx-trigger="click once" hx-target="#d1" hx-get="/test" value="foo"/>'); var div = make('<div id="d1"></div>'); input.click(); this.server.respond(); @@ -82,7 +82,7 @@ describe("kt-trigger attribute", function(){ }); this.server.autoRespond = true; this.server.autoRespondAfter = 0; - make('<div kt-trigger="every 10ms" kt-get="/test"/>'); + make('<div hx-trigger="every 10ms" hx-get="/test"/>'); }); diff --git a/test/core/ajax.js b/test/core/ajax.js index 763d4347..e7639033 100644 --- a/test/core/ajax.js +++ b/test/core/ajax.js @@ -1,4 +1,4 @@ -describe("Core kutty AJAX Tests", function(){ +describe("Core htmx AJAX Tests", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -13,7 +13,7 @@ describe("Core kutty AJAX Tests", function(){ { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-get="/test">Click Me!</button>') + var btn = make('<button hx-get="/test">Click Me!</button>') btn.click(); this.server.respond(); btn.innerHTML.should.equal("Clicked!"); @@ -21,13 +21,13 @@ describe("Core kutty AJAX Tests", function(){ it('processes inner content properly', function() { - this.server.respondWith("GET", "/test", '<a kt-get="/test2">Click Me</a>'); + this.server.respondWith("GET", "/test", '<a hx-get="/test2">Click Me</a>'); this.server.respondWith("GET", "/test2", "Clicked!"); - var div = make('<div kt-get="/test"></div>') + var div = make('<div hx-get="/test"></div>') div.click(); this.server.respond(); - div.innerHTML.should.equal('<a kt-get="/test2">Click Me</a>'); + div.innerHTML.should.equal('<a hx-get="/test2">Click Me</a>'); var a = div.querySelector('a'); a.click(); this.server.respond(); @@ -36,10 +36,10 @@ describe("Core kutty AJAX Tests", function(){ it('handles swap outerHTML properly', function() { - this.server.respondWith("GET", "/test", '<a id="a1" kt-get="/test2">Click Me</a>'); + this.server.respondWith("GET", "/test", '<a id="a1" hx-get="/test2">Click Me</a>'); this.server.respondWith("GET", "/test2", "Clicked!"); - var div = make('<div id="d1" kt-get="/test" kt-swap="outerHTML"></div>') + var div = make('<div id="d1" hx-get="/test" hx-swap="outerHTML"></div>') div.click(); should.equal(byId("d1"), div); this.server.respond(); @@ -54,11 +54,11 @@ describe("Core kutty AJAX Tests", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="beforebegin">*</div>') + var div = make('<div hx-get="/test" hx-swap="beforebegin">*</div>') var parent = div.parentElement; div.click(); this.server.respond(); @@ -84,11 +84,11 @@ describe("Core kutty AJAX Tests", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="afterbegin">*</div>') + var div = make('<div hx-get="/test" hx-swap="afterbegin">*</div>') div.click(); this.server.respond(); div.innerText.should.equal("1*"); @@ -111,11 +111,11 @@ describe("Core kutty AJAX Tests", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="afterbegin"></div>') + var div = make('<div hx-get="/test" hx-swap="afterbegin"></div>') div.click(); this.server.respond(); div.innerText.should.equal("1"); @@ -138,11 +138,11 @@ describe("Core kutty AJAX Tests", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="afterend">*</div>') + var div = make('<div hx-get="/test" hx-swap="afterend">*</div>') var parent = div.parentElement; div.click(); this.server.respond(); @@ -168,11 +168,11 @@ describe("Core kutty AJAX Tests", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="beforeend">*</div>') + var div = make('<div hx-get="/test" hx-swap="beforeend">*</div>') div.click(); this.server.respond(); div.innerText.should.equal("*1"); @@ -195,11 +195,11 @@ describe("Core kutty AJAX Tests", function(){ var i = 0; this.server.respondWith("GET", "/test", function(xhr){ i++; - xhr.respond(200, {}, '<a id="a' + i + '" kt-get="/test2" kt-swap="innerHTML">' + i + '</a>'); + xhr.respond(200, {}, '<a id="a' + i + '" hx-get="/test2" hx-swap="innerHTML">' + i + '</a>'); }); this.server.respondWith("GET", "/test2", "*"); - var div = make('<div kt-get="/test" kt-swap="beforeend"></div>') + var div = make('<div hx-get="/test" hx-swap="beforeend"></div>') div.click(); this.server.respond(); div.innerText.should.equal("1"); @@ -217,11 +217,11 @@ describe("Core kutty AJAX Tests", function(){ div.innerText.should.equal("**"); }); - it('handles kt-target properly', function() + it('handles hx-target properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var btn = make('<button kt-get="/test" kt-target="#s1">Click Me!</button>'); + var btn = make('<button hx-get="/test" hx-target="#s1">Click Me!</button>'); var target = make('<span id="s1">Initial</span>'); btn.click(); target.innerHTML.should.equal("Initial"); @@ -233,28 +233,28 @@ describe("Core kutty AJAX Tests", function(){ { this.server.respondWith("GET", "/test", [204, {}, "No Content!"]); - var btn = make('<button kt-get="/test">Click Me!</button>'); + var btn = make('<button hx-get="/test">Click Me!</button>'); btn.click(); btn.innerHTML.should.equal("Click Me!"); this.server.respond(); btn.innerHTML.should.equal("Click Me!"); }); - it('handles kt-trigger with non-default value', function() + it('handles hx-trigger with non-default value', function() { this.server.respondWith("GET", "/test", "Clicked!"); - var form = make('<form kt-get="/test" kt-trigger="click">Click Me!</form>'); + var form = make('<form hx-get="/test" hx-trigger="click">Click Me!</form>'); form.click(); form.innerHTML.should.equal("Click Me!"); this.server.respond(); form.innerHTML.should.equal("Clicked!"); }); - it('handles kt-trigger with load event', function() + it('handles hx-trigger with load event', function() { this.server.respondWith("GET", "/test", "Loaded!"); - var div = make('<div kt-get="/test" kt-trigger="load">Load Me!</div>'); + var div = make('<div hx-get="/test" hx-trigger="load">Load Me!</div>'); div.innerHTML.should.equal("Load Me!"); this.server.respond(); div.innerHTML.should.equal("Loaded!"); @@ -266,7 +266,7 @@ describe("Core kutty AJAX Tests", function(){ xhr.overriddenMimeType.should.equal("text/html"); done(); }); - var div = make('<div kt-get="/test">Click Me!</div>'); + var div = make('<div hx-get="/test">Click Me!</div>'); div.click(); this.server.respond(); }); @@ -278,28 +278,28 @@ describe("Core kutty AJAX Tests", function(){ xhr.respond(200, {}, "click " + i); i++ }); - var div = make('<div kt-get="/test"></div>'); + var div = make('<div hx-get="/test"></div>'); div.click(); div.click(); this.server.respond(); div.innerHTML.should.equal("click 1"); }); - it('properly handles kt-select for basic situation', function() + it('properly handles hx-select for basic situation', function() { var i = 1; this.server.respondWith("GET", "/test", "<div id='d1'>foo</div><div id='d2'>bar</div>"); - var div = make('<div kt-get="/test" kt-select="#d1"></div>'); + var div = make('<div hx-get="/test" hx-select="#d1"></div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("<div id=\"d1\">foo</div>"); }); - it('properly handles kt-select for full html document situation', function() + it('properly handles hx-select for full html document situation', function() { var i = 1; this.server.respondWith("GET", "/test", "<html><body><div id='d1'>foo</div><div id='d2'>bar</div></body></html>"); - var div = make('<div kt-get="/test" kt-select="#d1"></div>'); + var div = make('<div hx-get="/test" hx-select="#d1"></div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("<div id=\"d1\">foo</div>"); @@ -313,7 +313,7 @@ describe("Core kutty AJAX Tests", function(){ xhr.respond(204, {}, ""); }); - var form = make('<form kt-post="/test" kt-trigger="click">' + + var form = make('<form hx-post="/test" hx-trigger="click">' + '<input id="cb1" name="c1" value="cb1" type="checkbox">'+ '<input id="cb2" name="c1" value="cb2" type="checkbox">'+ '<input id="cb3" name="c1" value="cb3" type="checkbox">'+ diff --git a/test/core/api.js b/test/core/api.js index e5f51a26..4b4d1b2d 100644 --- a/test/core/api.js +++ b/test/core/api.js @@ -1,4 +1,4 @@ -describe("Core kutty API test", function(){ +describe("Core htmx API test", function(){ beforeEach(function() { this.server = makeServer(); clearWorkArea(); @@ -9,22 +9,22 @@ describe("Core kutty API test", function(){ }); it('version is correct', function(){ - kutty.version.should.equal("0.0.2"); + htmx.version.should.equal("0.0.2"); }); it('onLoad is called... onLoad', function(){ // also tests on/off - this.server.respondWith("GET", "/test", "<div id='d1' kt-get='/test'></div>") - var helper = kutty.onLoad(function (elt) { + this.server.respondWith("GET", "/test", "<div id='d1' hx-get='/test'></div>") + var helper = htmx.onLoad(function (elt) { elt.setAttribute("foo", "bar"); }); try { - var div = make("<div id='d1' kt-get='/test' kt-swap='outerHTML'></div>"); + var div = make("<div id='d1' hx-get='/test' hx-swap='outerHTML'></div>"); div.click(); this.server.respond(); byId("d1").getAttribute("foo").should.equal("bar"); } finally { - kutty.off("load.kutty", helper); + htmx.off("load.htmx", helper); } }); @@ -32,11 +32,11 @@ describe("Core kutty API test", function(){ var div = make("<div/>"); var myEventCalled = false; var detailStr = ""; - kutty.on("myEvent", function(evt){ + htmx.on("myEvent", function(evt){ myEventCalled = true; detailStr = evt.detail.str; }) - kutty.trigger(div, "myEvent", {str:"foo"}) + htmx.trigger(div, "myEvent", {str:"foo"}) myEventCalled.should.equal(true); detailStr.should.equal("foo"); @@ -44,55 +44,55 @@ describe("Core kutty API test", function(){ it('should find properly', function(){ var div = make("<div id='d1' class='c1 c2'>"); - div.should.equal(kutty.find("#d1")); - div.should.equal(kutty.find(".c1")); - div.should.equal(kutty.find(".c2")); - div.should.equal(kutty.find(".c1.c2")); + div.should.equal(htmx.find("#d1")); + div.should.equal(htmx.find(".c1")); + div.should.equal(htmx.find(".c2")); + div.should.equal(htmx.find(".c1.c2")); }); it('should find properly from elt', function(){ var div = make("<div><a id='a1'></a><a id='a2'></a></div>"); - kutty.find(div, "a").id.should.equal('a1'); + htmx.find(div, "a").id.should.equal('a1'); }); it('should find all properly', function(){ var div = make("<div class='c1 c2 c3'><div class='c1 c2'><div class='c1'>"); - kutty.findAll(".c1").length.should.equal(3); - kutty.findAll(".c2").length.should.equal(2); - kutty.findAll(".c3").length.should.equal(1); + htmx.findAll(".c1").length.should.equal(3); + htmx.findAll(".c2").length.should.equal(2); + htmx.findAll(".c3").length.should.equal(1); }); it('should find all properly from elt', function(){ var div = make("<div><div class='c1 c2 c3'><div class='c1 c2'><div class='c1'></div>"); - kutty.findAll(div, ".c1").length.should.equal(3); - kutty.findAll(div, ".c2").length.should.equal(2); - kutty.findAll(div,".c3").length.should.equal(1); + htmx.findAll(div, ".c1").length.should.equal(3); + htmx.findAll(div, ".c2").length.should.equal(2); + htmx.findAll(div,".c3").length.should.equal(1); }); it('should find closest element properly', function () { var div = make("<div><a id='a1'></a><a id='a2'></a></div>"); - var a = kutty.find(div, "a"); - kutty.closest(a, "div").should.equal(div); + var a = htmx.find(div, "a"); + htmx.closest(a, "div").should.equal(div); }); it('should remove element properly', function () { var div = make("<div><a></a></div>"); - var a = kutty.find(div, "a"); - kutty.remove(a); + var a = htmx.find(div, "a"); + htmx.remove(a); div.innerHTML.should.equal(""); }); it('should add class properly', function () { var div = make("<div></div>"); div.classList.contains("foo").should.equal(false); - kutty.addClass(div, "foo"); + htmx.addClass(div, "foo"); div.classList.contains("foo").should.equal(true); }); it('should add class properly after delay', function (done) { var div = make("<div></div>"); div.classList.contains("foo").should.equal(false); - kutty.addClass(div, "foo", 10); + htmx.addClass(div, "foo", 10); div.classList.contains("foo").should.equal(false); setTimeout(function () { div.classList.contains("foo").should.equal(true); @@ -102,17 +102,17 @@ describe("Core kutty API test", function(){ it('should remove class properly', function () { var div = make("<div></div>"); - kutty.addClass(div, "foo"); + htmx.addClass(div, "foo"); div.classList.contains("foo").should.equal(true); - kutty.removeClass(div, "foo"); + htmx.removeClass(div, "foo"); div.classList.contains("foo").should.equal(false); }); it('should add class properly after delay', function (done) { var div = make("<div></div>"); - kutty.addClass(div, "foo"); + htmx.addClass(div, "foo"); div.classList.contains("foo").should.equal(true); - kutty.removeClass(div, "foo", 10); + htmx.removeClass(div, "foo", 10); div.classList.contains("foo").should.equal(true); setTimeout(function () { div.classList.contains("foo").should.equal(false); @@ -123,9 +123,9 @@ describe("Core kutty API test", function(){ it('should toggle class properly', function () { var div = make("<div></div>"); div.classList.contains("foo").should.equal(false); - kutty.toggleClass(div, "foo"); + htmx.toggleClass(div, "foo"); div.classList.contains("foo").should.equal(true); - kutty.toggleClass(div, "foo"); + htmx.toggleClass(div, "foo"); div.classList.contains("foo").should.equal(false); }); @@ -138,19 +138,19 @@ describe("Core kutty API test", function(){ div2.classList.contains("foo").should.equal(false); div3.classList.contains("foo").should.equal(false); - kutty.takeClass(div1, "foo"); + htmx.takeClass(div1, "foo"); div1.classList.contains("foo").should.equal(true); div2.classList.contains("foo").should.equal(false); div3.classList.contains("foo").should.equal(false); - kutty.takeClass(div2, "foo"); + htmx.takeClass(div2, "foo"); div1.classList.contains("foo").should.equal(false); div2.classList.contains("foo").should.equal(true); div3.classList.contains("foo").should.equal(false); - kutty.takeClass(div3, "foo"); + htmx.takeClass(div3, "foo"); div1.classList.contains("foo").should.equal(false); div2.classList.contains("foo").should.equal(false); diff --git a/test/core/events.js b/test/core/events.js index 548f6e9f..68fc82ee 100644 --- a/test/core/events.js +++ b/test/core/events.js @@ -1,4 +1,4 @@ -describe("Core kutty Events", function() { +describe("Core htmx Events", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -8,24 +8,24 @@ describe("Core kutty Events", function() { clearWorkArea(); }); - it("load.kutty fires properly", function () { - var handler = kutty.on("load.kutty", function (evt) { + it("load.htmx fires properly", function () { + var handler = htmx.on("load.htmx", function (evt) { called = true; }); try { this.server.respondWith("GET", "/test", "<div></div>"); var called = false; - var div = make("<div kt-get='/test'></div>"); + var div = make("<div hx-get='/test'></div>"); div.click(); this.server.respond(); should.equal(called, true); } finally { - kutty.off("load.kutty", handler); + htmx.off("load.htmx", handler); } }); - it("configRequest.kutty allows attribute addition", function () { - var handler = kutty.on("configRequest.kutty", function (evt) { + it("configRequest.htmx allows attribute addition", function () { + var handler = htmx.on("configRequest.htmx", function (evt) { evt.detail.parameters['param'] = "true"; }); try { @@ -33,48 +33,48 @@ describe("Core kutty Events", function() { this.server.respondWith("POST", "/test", function (xhr) { param = parseParams(xhr.requestBody)['param']; }); - var div = make("<div kt-post='/test'></div>"); + var div = make("<div hx-post='/test'></div>"); div.click(); this.server.respond(); param.should.equal("true"); } finally { - kutty.off("configRequest.kutty", handler); + htmx.off("configRequest.htmx", handler); } }); - it("configRequest.kutty allows attribute removal", function () { + it("configRequest.htmx allows attribute removal", function () { var param = "foo"; - var handler = kutty.on("configRequest.kutty", function (evt) { + var handler = htmx.on("configRequest.htmx", function (evt) { delete evt.detail.parameters['param']; }); try { this.server.respondWith("POST", "/test", function (xhr) { param = parseParams(xhr.requestBody)['param']; }); - var div = make("<form kt-trigger='click' kt-post='/test'><input name='param' value='foo'></form>"); + var div = make("<form hx-trigger='click' hx-post='/test'><input name='param' value='foo'></form>"); div.click(); this.server.respond(); should.equal(param, undefined); } finally { - kutty.off("configRequest.kutty", handler); + htmx.off("configRequest.htmx", handler); } }); - it("configRequest.kutty allows header tweaking", function () { + it("configRequest.htmx allows header tweaking", function () { var header = "foo"; - var handler = kutty.on("configRequest.kutty", function (evt) { + var handler = htmx.on("configRequest.htmx", function (evt) { evt.detail.headers['X-My-Header'] = "bar"; }); try { this.server.respondWith("POST", "/test", function (xhr) { header = xhr.requestHeaders['X-My-Header']; }); - var div = make("<form kt-trigger='click' kt-post='/test'><input name='param' value='foo'></form>"); + var div = make("<form hx-trigger='click' hx-post='/test'><input name='param' value='foo'></form>"); div.click(); this.server.respond(); should.equal(header, "bar"); } finally { - kutty.off("configRequest.kutty", handler); + htmx.off("configRequest.htmx", handler); } }); diff --git a/test/core/headers.js b/test/core/headers.js index 2bd36e6a..a8192691 100644 --- a/test/core/headers.js +++ b/test/core/headers.js @@ -1,4 +1,4 @@ -describe("Core kutty AJAX headers", function() { +describe("Core htmx AJAX headers", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -13,7 +13,7 @@ describe("Core kutty AJAX headers", function() { xhr.requestHeaders['X-KT-Request'].should.be.equal('true'); xhr.respond(200, {}, ""); }); - var div = make('<div kt-get="/test"></div>'); + var div = make('<div hx-get="/test"></div>'); div.click(); this.server.respond(); }) @@ -23,7 +23,7 @@ describe("Core kutty AJAX headers", function() { xhr.requestHeaders['X-KT-Trigger'].should.equal('d1'); xhr.respond(200, {}, ""); }); - var div = make('<div id="d1" kt-get="/test"></div>'); + var div = make('<div id="d1" hx-get="/test"></div>'); div.click(); this.server.respond(); }) @@ -33,7 +33,7 @@ describe("Core kutty AJAX headers", function() { xhr.requestHeaders['X-KT-Trigger-Name'].should.equal('n1'); xhr.respond(200, {}, ""); }); - var div = make('<button name="n1" kt-get="/test"></button>'); + var div = make('<button name="n1" hx-get="/test"></button>'); div.click(); this.server.respond(); }) @@ -43,7 +43,7 @@ describe("Core kutty AJAX headers", function() { xhr.requestHeaders['X-KT-Target'].should.equal('d1'); xhr.respond(200, {}, ""); }); - var div = make('<div kt-target="#d1" kt-get="/test"></div><div id="d1" ></div>'); + var div = make('<div hx-target="#d1" hx-get="/test"></div><div id="d1" ></div>'); div.click(); this.server.respond(); }) @@ -51,7 +51,7 @@ describe("Core kutty AJAX headers", function() { it("should handle simple string X-KT-Trigger response header properly", function(){ this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "foo"}, ""]); - var div = make('<div kt-get="/test"></div>'); + var div = make('<div hx-get="/test"></div>'); var invokedEvent = false; div.addEventListener("foo", function (evt) { invokedEvent = true; @@ -64,7 +64,7 @@ describe("Core kutty AJAX headers", function() { it("should handle basic JSON X-KT-Trigger response header properly", function(){ this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "{\"foo\":null}"}, ""]); - var div = make('<div kt-get="/test"></div>'); + var div = make('<div hx-get="/test"></div>'); var invokedEvent = false; div.addEventListener("foo", function (evt) { invokedEvent = true; @@ -79,7 +79,7 @@ describe("Core kutty AJAX headers", function() { it("should handle JSON with array arg X-KT-Trigger response header properly", function(){ this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "{\"foo\":[1, 2, 3]}"}, ""]); - var div = make('<div kt-get="/test"></div>'); + var div = make('<div hx-get="/test"></div>'); var invokedEvent = false; div.addEventListener("foo", function (evt) { invokedEvent = true; @@ -94,7 +94,7 @@ describe("Core kutty AJAX headers", function() { it("should handle JSON with array arg X-KT-Trigger response header properly", function(){ this.server.respondWith("GET", "/test", [200, {"X-KT-Trigger" : "{\"foo\":{\"a\":1, \"b\":2}}"}, ""]); - var div = make('<div kt-get="/test"></div>'); + var div = make('<div hx-get="/test"></div>'); var invokedEvent = false; div.addEventListener("foo", function (evt) { invokedEvent = true; diff --git a/test/core/internals.js b/test/core/internals.js index 09cff001..9e6f139e 100644 --- a/test/core/internals.js +++ b/test/core/internals.js @@ -1,4 +1,4 @@ -describe("Core kutty internals Tests", function() { +describe("Core htmx internals Tests", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -9,15 +9,15 @@ describe("Core kutty internals Tests", function() { }); it("makeFragment works with janky stuff", function(){ - kutty._("makeFragment")("<html></html>").tagName.should.equal("BODY"); - kutty._("makeFragment")("<html><body></body></html>").tagName.should.equal("BODY"); + htmx._("makeFragment")("<html></html>").tagName.should.equal("BODY"); + htmx._("makeFragment")("<html><body></body></html>").tagName.should.equal("BODY"); //NB - the tag name should be the *parent* element hosting the HTML since we use the fragment children // for the swap - kutty._("makeFragment")("<td></td>").tagName.should.equal("TR"); - kutty._("makeFragment")("<thead></thead>").tagName.should.equal("TABLE"); - kutty._("makeFragment")("<col></col>").tagName.should.equal("COLGROUP"); - kutty._("makeFragment")("<tr></tr>").tagName.should.equal("TBODY"); + htmx._("makeFragment")("<td></td>").tagName.should.equal("TR"); + htmx._("makeFragment")("<thead></thead>").tagName.should.equal("TABLE"); + htmx._("makeFragment")("<col></col>").tagName.should.equal("COLGROUP"); + htmx._("makeFragment")("<tr></tr>").tagName.should.equal("TBODY"); }) });
\ No newline at end of file diff --git a/test/core/parameters.js b/test/core/parameters.js index 519f3ca8..6233e7ae 100644 --- a/test/core/parameters.js +++ b/test/core/parameters.js @@ -1,4 +1,4 @@ -describe("Core kutty Parameter Handling", function() { +describe("Core htmx Parameter Handling", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -10,20 +10,20 @@ describe("Core kutty Parameter Handling", function() { it('Input includes value', function () { var input = make('<input name="foo" value="bar"/>'); - var vals = kutty._('getInputValues')(input); + var vals = htmx._('getInputValues')(input); vals['foo'].should.equal('bar'); }) it('Input includes value on get', function () { var input = make('<input name="foo" value="bar"/>'); - var vals = kutty._('getInputValues')(input, "get"); + var vals = htmx._('getInputValues')(input, "get"); vals['foo'].should.equal('bar'); }) it('Input includes form', function () { var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>'); var input = byId('i1'); - var vals = kutty._('getInputValues')(input); + var vals = htmx._('getInputValues')(input); vals['foo'].should.equal('bar'); vals['do'].should.equal('rey'); }) @@ -31,7 +31,7 @@ describe("Core kutty Parameter Handling", function() { it('Input doesnt include form on get', function () { var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>'); var input = byId('i1'); - var vals = kutty._('getInputValues')(input, 'get'); + var vals = htmx._('getInputValues')(input, 'get'); vals['foo'].should.equal('bar'); should.equal(vals['do'], undefined); }) @@ -39,75 +39,75 @@ describe("Core kutty Parameter Handling", function() { it('non-input includes form', function () { var form = make('<form><div id="d1"/><input id="i2" name="do" value="rey"/></form>'); var div = byId('d1'); - var vals = kutty._('getInputValues')(div, "post"); + var vals = htmx._('getInputValues')(div, "post"); vals['do'].should.equal('rey'); }) it('non-input doesnt include form on get', function () { var form = make('<form><div id="d1"/><input id="i2" name="do" value="rey"/></form>'); var div = byId('d1'); - var vals = kutty._('getInputValues')(div, "get"); + var vals = htmx._('getInputValues')(div, "get"); should.equal(vals['do'], undefined); }) it('Basic form works on get', function () { var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>'); - var vals = kutty._('getInputValues')(form, 'get'); + var vals = htmx._('getInputValues')(form, 'get'); vals['foo'].should.equal('bar'); vals['do'].should.equal('rey'); }) it('Basic form works on non-get', function () { var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/></form>'); - var vals = kutty._('getInputValues')(form, 'post'); + var vals = htmx._('getInputValues')(form, 'post'); vals['foo'].should.equal('bar'); vals['do'].should.equal('rey'); }) it('Double values are included as array', function () { var form = make('<form><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>'); - var vals = kutty._('getInputValues')(form); + var vals = htmx._('getInputValues')(form); vals['foo'].should.equal('bar'); vals['do'].should.deep.equal(['rey', 'rey']); }) - it('kt-include works with form', function () { + it('hx-include works with form', function () { var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>'); - var div = make('<div kt-include="#f1"></div>'); - var vals = kutty._('getInputValues')(div); + var div = make('<div hx-include="#f1"></div>'); + var vals = htmx._('getInputValues')(div); vals['foo'].should.equal('bar'); vals['do'].should.deep.equal(['rey', 'rey']); }) - it('kt-include works with input', function () { + it('hx-include works with input', function () { var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>'); - var div = make('<div kt-include="#i1"></div>'); - var vals = kutty._('getInputValues')(div); + var div = make('<div hx-include="#i1"></div>'); + var vals = htmx._('getInputValues')(div); vals['foo'].should.equal('bar'); should.equal(vals['do'], undefined); }) - it('kt-include works with two inputs', function () { + it('hx-include works with two inputs', function () { var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>'); - var div = make('<div kt-include="#i1, #i2"></div>'); - var vals = kutty._('getInputValues')(div); + var div = make('<div hx-include="#i1, #i2"></div>'); + var vals = htmx._('getInputValues')(div); vals['foo'].should.equal('bar'); vals['do'].should.deep.equal(['rey', 'rey']); }) - it('kt-include works with two inputs, plus form', function () { + it('hx-include works with two inputs, plus form', function () { var form = make('<form id="f1"><input id="i1" name="foo" value="bar"/><input id="i2" name="do" value="rey"/><input id="i2" name="do" value="rey"/></form>'); - var div = make('<div kt-include="#i1, #i2, #f1"></div>'); - var vals = kutty._('getInputValues')(div); + var div = make('<div hx-include="#i1, #i2, #f1"></div>'); + var vals = htmx._('getInputValues')(div); vals['foo'].should.equal('bar'); vals['do'].should.deep.equal(['rey', 'rey']); }) it('correctly URL escapes values', function () { - kutty._("urlEncode")({}).should.equal(""); - kutty._("urlEncode")({"foo": "bar"}).should.equal("foo=bar"); - kutty._("urlEncode")({"foo": "bar", "do" : "rey"}).should.equal("foo=bar&do=rey"); - kutty._("urlEncode")({"foo": "bar", "do" : ["rey", "blah"]}).should.equal("foo=bar&do=rey&do=blah"); + htmx._("urlEncode")({}).should.equal(""); + htmx._("urlEncode")({"foo": "bar"}).should.equal("foo=bar"); + htmx._("urlEncode")({"foo": "bar", "do" : "rey"}).should.equal("foo=bar&do=rey"); + htmx._("urlEncode")({"foo": "bar", "do" : ["rey", "blah"]}).should.equal("foo=bar&do=rey&do=blah"); }); }); diff --git a/test/core/regressions.js b/test/core/regressions.js index 45fa6778..e8c95e25 100644 --- a/test/core/regressions.js +++ b/test/core/regressions.js @@ -1,4 +1,4 @@ -describe("Core kutty Regression Tests", function(){ +describe("Core htmx Regression Tests", function(){ beforeEach(function() { this.server = makeServer(); @@ -18,21 +18,21 @@ describe("Core kutty Regression Tests", function(){ '</svg>') }); - it ('Handles https://github.com/bigskysoftware/kutty/issues/4 properly', function() { + it ('Handles https://github.com/bigskysoftware/htmx/issues/4 properly', function() { this.server.respondWith("GET", "/index2a.php", - "<div id='message' kt-swap-oob='true'>I came from message oob swap I should be second</div>" + - "<div id='message2' kt-swap-oob='true'>I came from a message2 oob swap I should be third but I am in the wrong spot</div>" + + "<div id='message' hx-swap-oob='true'>I came from message oob swap I should be second</div>" + + "<div id='message2' hx-swap-oob='true'>I came from a message2 oob swap I should be third but I am in the wrong spot</div>" + "I'm page2 content (non-swap) I should be first") - var h1 = make("<h1 kt-get='/index2a.php' kt-target='#page2' kt-trigger='click'>Kutty CLICK ME</h1>" + + var h1 = make("<h1 hx-get='/index2a.php' hx-target='#page2' hx-trigger='click'>Kutty CLICK ME</h1>" + "<div id='page2' ></div>" + "<div id='message'></div>" + "<div id='message2'></div>") h1.click(); this.server.respond(); - kutty.find("#page2").innerHTML.should.equal("I'm page2 content (non-swap) I should be first") - kutty.find("#message").innerHTML.should.equal("I came from message oob swap I should be second") - kutty.find("#message2").innerHTML.should.equal("I came from a message2 oob swap I should be third but I am in the wrong spot") + htmx.find("#page2").innerHTML.should.equal("I'm page2 content (non-swap) I should be first") + htmx.find("#message").innerHTML.should.equal("I came from message oob swap I should be second") + htmx.find("#message2").innerHTML.should.equal("I came from a message2 oob swap I should be third but I am in the wrong spot") }); }) diff --git a/test/core/verbs.js b/test/core/verbs.js index ec85d5f6..1d0711c2 100644 --- a/test/core/verbs.js +++ b/test/core/verbs.js @@ -1,4 +1,4 @@ -describe("Core kutty AJAX Verbs", function() { +describe("Core htmx AJAX Verbs", function() { beforeEach(function () { this.server = makeServer(); clearWorkArea(); @@ -10,7 +10,7 @@ describe("Core kutty AJAX Verbs", function() { it('handles basic posts properly', function () { this.server.respondWith("POST", "/test", "post"); - var div = make('<div kt-post="/test">click me</div>'); + var div = make('<div hx-post="/test">click me</div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("post"); @@ -18,7 +18,7 @@ describe("Core kutty AJAX Verbs", function() { it('handles basic put properly', function () { this.server.respondWith("PUT", "/test", "put"); - var div = make('<div kt-put="/test">click me</div>'); + var div = make('<div hx-put="/test">click me</div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("put"); @@ -26,7 +26,7 @@ describe("Core kutty AJAX Verbs", function() { it('handles basic patch properly', function () { this.server.respondWith("PATCH", "/test", "patch"); - var div = make('<div kt-patch="/test">click me</div>'); + var div = make('<div hx-patch="/test">click me</div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("patch"); @@ -34,7 +34,7 @@ describe("Core kutty AJAX Verbs", function() { it('handles basic delete properly', function () { this.server.respondWith("DELETE", "/test", "delete"); - var div = make('<div kt-delete="/test">click me</div>'); + var div = make('<div hx-delete="/test">click me</div>'); div.click(); this.server.respond(); div.innerHTML.should.equal("delete"); diff --git a/test/index.html b/test/index.html index ac259016..a8ce9899 100644 --- a/test/index.html +++ b/test/index.html @@ -9,11 +9,11 @@ <meta http-equiv="expires" content="0" /> <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" /> <meta http-equiv="pragma" content="no-cache" /> - <meta name="kutty-config" content='{"historyEnabled":false}'> + <meta name="htmx-config" content='{"historyEnabled":false}'> </head> <body style="padding:20px;font-family: sans-serif"> -<h1>kutty.js test suite</h1> +<h1>htmx.js test suite</h1> <h2>Scratch Page</h2> <ul> @@ -43,7 +43,7 @@ <script src="../node_modules/chai/chai.js"></script> <script src="../node_modules/mocha/mocha.js"></script> <script src="../node_modules/sinon/pkg/sinon.js"></script> -<script src="../src/kutty.js"></script> +<script src="../src/htmx.js"></script> <script class="mocha-init"> mocha.setup('bdd'); mocha.checkLeaks(); @@ -62,22 +62,22 @@ <script src="core/regressions.js"></script> <!-- attribute tests --> -<script src="attributes/kt-boost.js"></script> -<script src="attributes/kt-classes.js"></script> -<script src="attributes/kt-delete.js"></script> -<script src="attributes/kt-error-url.js"></script> -<script src="attributes/kt-get.js"></script> -<script src="attributes/kt-include.js"></script> -<script src="attributes/kt-indicator.js"></script> -<script src="attributes/kt-params.js"></script> -<script src="attributes/kt-patch.js"></script> -<script src="attributes/kt-post.js"></script> -<script src="attributes/kt-push-url.js"></script> -<script src="attributes/kt-put.js"></script> -<script src="attributes/kt-swap-oob.js"></script> -<script src="attributes/kt-swap.js"></script> -<script src="attributes/kt-target.js"></script> -<script src="attributes/kt-trigger.js"></script> +<script src="attributes/hx-boost.js"></script> +<script src="attributes/hx-classes.js"></script> +<script src="attributes/hx-delete.js"></script> +<script src="attributes/hx-error-url.js"></script> +<script src="attributes/hx-get.js"></script> +<script src="attributes/hx-include.js"></script> +<script src="attributes/hx-indicator.js"></script> +<script src="attributes/hx-params.js"></script> +<script src="attributes/hx-patch.js"></script> +<script src="attributes/hx-post.js"></script> +<script src="attributes/hx-push-url.js"></script> +<script src="attributes/hx-put.js"></script> +<script src="attributes/hx-swap-oob.js"></script> +<script src="attributes/hx-swap.js"></script> +<script src="attributes/hx-target.js"></script> +<script src="attributes/hx-trigger.js"></script> <!-- events last so they don't screw up other tests --> <script src="core/events.js"></script> @@ -90,7 +90,7 @@ </script> <em>Work Area</em> <hr/> -<div id="work-area" kt-history-elt> +<div id="work-area" hx-history-elt> </div> </body> </html> diff --git a/test/manual/browser-only-tests.html b/test/manual/browser-only-tests.html index 7ef37eb5..f9c7c093 100644 --- a/test/manual/browser-only-tests.html +++ b/test/manual/browser-only-tests.html @@ -10,7 +10,7 @@ <script src="../../node_modules/chai/chai.js"></script> <script src="../../node_modules/mocha/mocha.js"></script> <script src="../../node_modules/sinon/pkg/sinon.js"></script> -<script src="../../src/kutty.js"></script> +<script src="../../src/htmx.js"></script> <script class="mocha-init"> mocha.setup('bdd'); mocha.checkLeaks(); @@ -34,7 +34,7 @@ this.server.respondWith("GET", "/test", "second"); getWorkArea().innerHTML.should.be.equal(""); - var div = make('<div kt-push-url="true" kt-get="/test">first</div>'); + var div = make('<div hx-push-url="true" hx-get="/test">first</div>'); div.click(); this.server.respond(); getWorkArea().textContent.should.equal("second") @@ -53,7 +53,7 @@ }); getWorkArea().innerHTML.should.equal(""); - var div = make('<div kt-push-url="true" kt-get="/test" class="">0</div>'); + var div = make('<div hx-push-url="true" hx-get="/test" class="">0</div>'); div.click(); this.server.respond(); getWorkArea().textContent.should.equal("1") @@ -77,7 +77,7 @@ this.server.respondWith("GET", "/test", "second"); getWorkArea().innerHTML.should.equal(""); - var div = make('<div kt-push-url="true" kt-get="/test" class="">first</div>'); + var div = make('<div hx-push-url="true" hx-get="/test" class="">first</div>'); div.click(); this.server.respond(); getWorkArea().textContent.should.equal("second") @@ -104,7 +104,7 @@ </script> <em>Work Area</em> <hr/> -<div id="work-area" kt-history-elt> +<div id="work-area" hx-history-elt> </div> </body> </html> diff --git a/test/manual/confirm-and-prompt.html b/test/manual/confirm-and-prompt.html index 4590544e..07934384 100644 --- a/test/manual/confirm-and-prompt.html +++ b/test/manual/confirm-and-prompt.html @@ -2,11 +2,11 @@ <head> <meta charset="utf-8" /> <title>Test if indicators are invisible by default</title> - <script src="../../src/kutty.js"></script> + <script src="../../src/htmx.js"></script> </head> <body style="padding:20px;font-family: sans-serif"> <script src="../../node_modules/sinon/pkg/sinon.js"></script> -<script src="../../src/kutty.js"></script> +<script src="../../src/htmx.js"></script> <script src="../util/util.js"></script> <script> server = makeServer(); @@ -19,10 +19,10 @@ }) </script> <h1>Prompt & Confirm Tests</h1> -<button kt-get="/prompt" kt-prompt="Enter some text and it should be echoed in this button">Click For Prompt</button> +<button hx-get="/prompt" hx-prompt="Enter some text and it should be echoed in this button">Click For Prompt</button> <br/> <br/> <br/> -<button kt-get="/confirm" kt-confirm="Confirm The Action">Click For Confirm</button> +<button hx-get="/confirm" hx-confirm="Confirm The Action">Click For Confirm</button> </body> </html> diff --git a/test/manual/no-indicator-css.html b/test/manual/no-indicator-css.html index d24753a0..0ce4e9fc 100644 --- a/test/manual/no-indicator-css.html +++ b/test/manual/no-indicator-css.html @@ -1,9 +1,9 @@ <html lang="en"> <head> <meta charset="utf-8" /> - <meta name="kutty-config" content='{"includeIndicatorStyles":false}'> + <meta name="htmx-config" content='{"includeIndicatorStyles":false}'> <title>Test if the includeIndicatorStyles meta option works</title> - <script src="../../src/kutty.js"></script> + <script src="../../src/htmx.js"></script> </head> <body style="padding:20px;font-family: sans-serif"> <h1>You should see bars here:</h1> @@ -11,6 +11,6 @@ We are overriding the normal CSS inclusion with the meta directive <code>{"includeIndicatorStyles":false}</code> so you should see the indicator because it is not being hidden by the default classes. </p> - <img class="kutty-indicator" src="../img/bars.svg" width="200"> + <img class="htmx-indicator" src="../img/bars.svg" width="200"> </body> </html> diff --git a/test/manual/yes-indicator-css.html b/test/manual/yes-indicator-css.html index 46fdea72..fc2e02a1 100644 --- a/test/manual/yes-indicator-css.html +++ b/test/manual/yes-indicator-css.html @@ -2,10 +2,10 @@ <head> <meta charset="utf-8" /> <title>Test if indicators are invisible by default</title> - <script src="../../src/kutty.js"></script> + <script src="../../src/htmx.js"></script> </head> <body style="padding:20px;font-family: sans-serif"> <h1>You should not see bars here:</h1> - <img class="kutty-indicator" src="../img/bars.svg" width="200"> + <img class="htmx-indicator" src="../img/bars.svg" width="200"> </body> </html> diff --git a/test/scratch.html b/test/scratch.html index c800a437..f3ba5b56 100644 --- a/test/scratch.html +++ b/test/scratch.html @@ -9,7 +9,7 @@ opacity: 0; } - .kt-show-indicator .indicator { + .hx-show-indicator .indicator { opacity: 100%; } @@ -19,18 +19,18 @@ </head> <body style="padding:20px;font-family: sans-serif"> <script src="../node_modules/sinon/pkg/sinon.js"></script> -<script src="../src/kutty.js"></script> +<script src="../src/htmx.js"></script> <script src="util/util.js"></script> <script src="util/scratch_server.js"></script> <script> - // this.server.respondWith("GET", "/test", '<a kt-get="/test2">Click Me</a>'); + // this.server.respondWith("GET", "/test", '<a hx-get="/test2">Click Me</a>'); // this.server.respondWith("GET", "/test2", "Clicked!"); // - // make('<div kt-get="/test">dd</div>') + // make('<div hx-get="/test">dd</div>') this.server.respondWith("GET", "/test", '<div id="d1" style="color: red; margin: 100px">Foo</div>'); - make('<div kt-swap="outerHTML" kt-get="/test" kt-push-url="true" id="d1">Foo</div>'); + make('<div hx-swap="outerHTML" hx-get="/test" hx-push-url="true" id="d1">Foo</div>'); </script> @@ -43,7 +43,7 @@ Autorespond: <input id="autorespond" type="checkbox" onclick="toggleAutoRespond( <em>Work Area</em> <hr/> -<div id="work-area" kt-history-elt> +<div id="work-area" hx-history-elt> </div> diff --git a/test/util/scratch_server.js b/test/util/scratch_server.js index 187590dd..bbf5a87c 100644 --- a/test/util/scratch_server.js +++ b/test/util/scratch_server.js @@ -1,5 +1,5 @@ var server = makeServer(); -var autoRespond = localStorage.getItem('kt-scratch-autorespond') == "true"; +var autoRespond = localStorage.getItem('hx-scratch-autorespond') == "true"; server.autoRespond = autoRespond; ready(function () { if (autoRespond) { @@ -8,10 +8,10 @@ ready(function () { }) function toggleAutoRespond() { if (server.autoRespond) { - localStorage.removeItem('kt-scratch-autorespond'); + localStorage.removeItem('hx-scratch-autorespond'); server.autoRespond = false; } else { - localStorage.setItem('kt-scratch-autorespond', 'true'); + localStorage.setItem('hx-scratch-autorespond', 'true'); server.autoRespond = true; } } diff --git a/test/util/util.js b/test/util/util.js index 8b38d190..66f2dc4b 100644 --- a/test/util/util.js +++ b/test/util/util.js @@ -1,6 +1,6 @@ /* Test Utilities */ -kutty.logAll(); +htmx.logAll(); function byId(id) { return document.getElementById(id); @@ -13,7 +13,7 @@ function make(htmlStr) { var wa = getWorkArea(); for (var i = fragment.childNodes.length - 1; i >= 0; i--) { var child = fragment.childNodes[i]; - kutty.process(child); + htmx.process(child); wa.appendChild(child); } return wa.lastChild; diff --git a/www/_includes/layout.njk b/www/_includes/layout.njk index 9a1676dc..79e22550 100644 --- a/www/_includes/layout.njk +++ b/www/_includes/layout.njk @@ -1,19 +1,19 @@ <html lang="en"> <head> - <title></> kutty - high power tools for html</title> + <title></> htmx - high power tools for html</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/css/site.css"/> - <link rel="stylesheet" href="/css/prism-kutty.css"/> + <link rel="stylesheet" href="/css/prism-htmx.css"/> <script src="https://unpkg.com/prismjs@1.20.0/components/prism-core.min.js"></script> <script src="https://unpkg.com/prismjs@1.20.0/plugins/autoloader/prism-autoloader.min.js"></script> - <script src="/js/kutty.js"></script> + <script src="/js/htmx.js"></script> <script> - kutty.logger = function(elt, event, data) { + htmx.logger = function(elt, event, data) { if(console) { //console.log(event, elt, data); } } - kutty.onLoad(function(){ + htmx.onLoad(function(){ Prism.highlightAll(); }) </script> @@ -24,9 +24,9 @@ <div class="row"> <div class="2 col"> {% if page.url.indexOf("/examples/") == 0 %} - <span onclick="document.location = '/';" class="logo light"><<a>/</a>> k<a>u</a>tty</span> + <span onclick="document.location = '/';" class="logo light"><<a>/</a>> htm<a>x</a></span> {% else %} - <span kt-get="/" kt-target="body" kt-push-url="true" class="logo light"><<a>/</a>> k<a>u</a>tty</span> + <span hx-get="/" hx-target="body" hx-push-url="true" class="logo light"><<a>/</a>> htm<a>x</a></span> {% endif %} <svg onclick="document.getElementById('nav').classList.toggle('show')" class="hamburger" viewBox="0 0 100 80" width="25" height="25" style="margin-bottom:-5px"> <rect width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect> @@ -37,7 +37,7 @@ {% if page.url.indexOf("/examples/") == 0 %} <div id="nav" class="10 col nav"> <!-- don't boost on demo pages, sinon hijacks everything :/ --> {% else %} - <div id="nav" class="10 col" kt-boost="true"> + <div id="nav" class="10 col" hx-boost="true"> {% endif %} <div class="row"> <div class="1 col"> @@ -55,8 +55,8 @@ <div class="8 col"> </div> <div class="8 col" style="text-align: right"> - <a href="https://github.com/bigskysoftware/kutty">github</a> - <iframe style="margin:auto;" src="https://ghbtns.com/github-btn.html?user=bigskysoftware&repo=kutty&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="Star twbs/bootstrap on GitHub"></iframe> + <a href="https://github.com/bigskysoftware/htmx">github</a> + <iframe style="margin:auto;" src="https://ghbtns.com/github-btn.html?user=bigskysoftware&repo=htmx&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="Star twbs/bootstrap on GitHub"></iframe> </div> </div> </div> diff --git a/www/attributes/kt-boost.md b/www/attributes/hx-boost.md index 99d58525..a6ab1742 100644 --- a/www/attributes/kt-boost.md +++ b/www/attributes/hx-boost.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - kt-boost +title: </> htmx - hx-boost --- -## `kt-boost` +## `hx-boost` -The `kt-boost` attribute allows you to "boost" normal anchors and form tags to use AJAX instead. This +The `hx-boost` attribute allows you to "boost" normal anchors and form tags to use AJAX instead. This has the [nice fallback](https://en.wikipedia.org/wiki/Progressive_enhancement) that, if the user does not have javascript enabled, the site will continue to work. @@ -21,7 +21,7 @@ swap will be used. Here is an example of some boosted links: ```html -<div kt-boost="true"> +<div hx-boost="true"> <a href="/page1">Go To Page 1</a> <a href="/page2">Go To Page 2</a> </div> @@ -29,6 +29,6 @@ Here is an example of some boosted links: ### Notes -* `kt-boost` is inherited and can be placed on a parent element +* `hx-boost` is inherited and can be placed on a parent element * Only links that are to the same domain and that are not local anchors will be boosted * All requests are done via AJAX, so keep that in mind when doing things like redirects
\ No newline at end of file diff --git a/www/attributes/kt-classes.md b/www/attributes/hx-classes.md index 87ca3844..37f9f846 100644 --- a/www/attributes/kt-classes.md +++ b/www/attributes/hx-classes.md @@ -1,15 +1,15 @@ --- layout: layout.njk -title: </> kutty - kt-classes +title: </> htmx - hx-classes --- -## `kt-classes` +## `hx-classes` -The `kt-classes` attribute allows you to specify CSS classes that will be swapped onto the element that +The `hx-classes` attribute allows you to specify CSS classes that will be swapped onto the element that the attribute is on. This allows you to apply [CSS Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions) to your HTML without resorting to javascript. -A `kt-classes` attribute value consists of "runs", which are separated by an `&` character. All +A `hx-classes` attribute value consists of "runs", which are separated by an `&` character. All class operations within a given run will be applied sequentially, with the delay specified. Within a run, a `,` character separates distinct class operations. @@ -20,16 +20,16 @@ optionally followed by a colon `:` and a time delay. Here are some examples: ```html -<div kt-classes="add foo"/> <!-- adds the class "foo" after 100ms --> -<div kt-classes="remove bar:1s"/> <!-- removes the class "bar" after 1s --> -<div kt-classes="remove bar:1s, add foo:1s"/> <!-- removes the class "bar" after 1s +<div hx-classes="add foo"/> <!-- adds the class "foo" after 100ms --> +<div hx-classes="remove bar:1s"/> <!-- removes the class "bar" after 1s --> +<div hx-classes="remove bar:1s, add foo:1s"/> <!-- removes the class "bar" after 1s then adds the class "foo" 1s after that --> -<div kt-classes="remove bar:1s & add foo:1s"/> <!-- removes the class "bar" and adds +<div hx-classes="remove bar:1s & add foo:1s"/> <!-- removes the class "bar" and adds class "foo" after 1s --> -<div kt-classes="toggle foo:1s"/> <!-- toggles the class "foo" every 1s --> +<div hx-classes="toggle foo:1s"/> <!-- toggles the class "foo" every 1s --> ``` ### Notes -* `kt-classes` is not inherited +* `hx-classes` is not inherited * The default delay if none is specified is 100ms diff --git a/www/attributes/kt-confirm.md b/www/attributes/hx-confirm.md index f8608724..5de0186b 100644 --- a/www/attributes/kt-confirm.md +++ b/www/attributes/hx-confirm.md @@ -1,21 +1,21 @@ --- layout: layout.njk -title: </> kutty - kt-confirm +title: </> htmx - hx-confirm --- -## `kt-confirm` +## `hx-confirm` -The `kt-confirm` attribute allows you to confirm an action before issuing a request. This can be useful +The `hx-confirm` attribute allows you to confirm an action before issuing a request. This can be useful in cases where the action is destructive and you want to ensure that the user really wants to do it. Here is an example: ```html -<button kt-delete="/account" kt-confirm="Are you sure you wish to delete your account?"> +<button hx-delete="/account" hx-confirm="Are you sure you wish to delete your account?"> Delete My Account </button> ``` ### Notes -* `kt-confirm` is inherited and can be placed on a parent element +* `hx-confirm` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-delete.md b/www/attributes/hx-delete.md index a41a05a6..561e15bd 100644 --- a/www/attributes/kt-delete.md +++ b/www/attributes/hx-delete.md @@ -1,15 +1,15 @@ --- layout: layout.njk -title: </> kutty - kt-delete +title: </> htmx - hx-delete --- -## `kt-delete` +## `hx-delete` -The `kt-delete` attribute will cause an element to issue a `DELETE` to the specified URL and swap +The `hx-delete` attribute will cause an element to issue a `DELETE` to the specified URL and swap the HTML into the DOM using a swap strategy: ```html -<button kt-delete="/account" kt-target="body"> +<button hx-delete="/account" hx-target="body"> Delete Your Account </button> ``` @@ -19,9 +19,9 @@ This example will cause the `button` to issue a `DELETE` to `/account` and swap ### Notes -* `kt-delete` is not inherited +* `hx-delete` is not inherited * Since most browsers do not support issuing an actual `DELETE`, the request will actually be issued as a `POST`, with the [`X-HTTP-Method-Override`](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields) header set to `DELETE`. -* You can control the target of the swap using the [kt-target](/attributes/kt-target) attribute -* You can control the swap strategy by using the [kt-swap](/attributes/kt-swap) attribute -* You can control what event triggers the request with the [kt-trigger](/attributes/kt-trigger) attribute +* You can control the target of the swap using the [hx-target](/attributes/hx-target) attribute +* You can control the swap strategy by using the [hx-swap](/attributes/hx-swap) attribute +* You can control what event triggers the request with the [hx-trigger](/attributes/hx-trigger) attribute diff --git a/www/attributes/hx-error-url.md b/www/attributes/hx-error-url.md new file mode 100644 index 00000000..b6d2715b --- /dev/null +++ b/www/attributes/hx-error-url.md @@ -0,0 +1,24 @@ +--- +layout: layout.njk +title: </> htmx - hx-error-url +--- + +## `hx-error-url` + +The `hx-error-url` attribute allows you to send client-side errors to a specified URL. It is typically put on the +body tag, so all errors are caught and send to the server. + +```html +<body hx-error-url="/errors">\ + +</body> +``` +When a client side error is caught by htmx it will be `POST`-ed to the given URL, with the following JSON format: + +```json + { "elt": elt.id, "event": eventName, "detail" : detail } +``` + +### Notes + +* `hx-error-url` is inherited and can be placed on a parent element diff --git a/www/attributes/hx-get.md b/www/attributes/hx-get.md new file mode 100644 index 00000000..8a1d1185 --- /dev/null +++ b/www/attributes/hx-get.md @@ -0,0 +1,25 @@ +--- +layout: layout.njk +title: </> htmx - hx-get +--- + +## `hx-get` + +The `hx-get` attribute will cause an element to issue a `GET` to the specified URL and swap +the HTML into the DOM using a swap strategy: + +```html + <div hx-get="/example">Get Some HTML</div> +``` + +This example will cause the `div` to issue a `GET` to `/example` and swap the returned HTML into + the `innerHTML` of the `div`. + +### Notes + +* `hx-get` is not inherited +* By default `hx-get` does not include any parameters. You can use the [hx-params](/attributes/hx-params) + attribute to change this +* You can control the target of the swap using the [hx-target](/attributes/hx-target) attribute +* You can control the swap strategy by using the [hx-swap](/attributes/hx-swap) attribute +* You can control what event triggers the request with the [hx-trigger](/attributes/hx-trigger) attribute diff --git a/www/attributes/kt-history-elt.md b/www/attributes/hx-history-elt.md index d074c254..addc1ddb 100644 --- a/www/attributes/kt-history-elt.md +++ b/www/attributes/hx-history-elt.md @@ -1,14 +1,14 @@ --- layout: layout.njk -title: </> kutty - kt-history-elt +title: </> htmx - hx-history-elt --- -## `kt-history-elt` +## `hx-history-elt` -The `kt-history-elt` attribute allows you to specify the element that will be used to snapshot and +The `hx-history-elt` attribute allows you to specify the element that will be used to snapshot and restore page state during navigation. By default, the `body` tag is used. This is typically good enough for most setups, but you may want to narrow it down to a child element. Just make -sure that the element is always visible in your application, or kutty will not be able to restore +sure that the element is always visible in your application, or htmx will not be able to restore history navigation properly. @@ -17,7 +17,7 @@ Here is an example: ```html <html> <body> -<div id="content" kt-history-elt> +<div id="content" hx-history-elt> ... </div> </body> @@ -26,5 +26,5 @@ Here is an example: ### Notes -* `kt-history-elt` is not inherited +* `hx-history-elt` is not inherited * In most cases we don't recommend narrowing the history snapshot
\ No newline at end of file diff --git a/www/attributes/kt-include.md b/www/attributes/hx-include.md index 5b624a22..f608539e 100644 --- a/www/attributes/kt-include.md +++ b/www/attributes/hx-include.md @@ -1,18 +1,18 @@ --- layout: layout.njk -title: </> kutty - kt-include +title: </> htmx - hx-include --- -## `kt-include` +## `hx-include` -The `kt-include` attribute allows you to include additional element values in an AJAX request. The value of +The `hx-include` attribute allows you to include additional element values in an AJAX request. The value of this attribute is a CSS query selector of the element or elements to include in the query. Here is an example that includes a separate input value: ```html <div> - <button kt-post="/register" kt-include="[name='email']"> + <button hx-post="/register" hx-include="[name='email']"> Register! </button> Enter email: <input name="email" type="email"/> @@ -24,4 +24,4 @@ the value automatically, but it demonstrates the concept. ### Notes -* `kt-include` is inherited and can be placed on a parent element +* `hx-include` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-indicator.md b/www/attributes/hx-indicator.md index 77992864..5a35a182 100644 --- a/www/attributes/kt-indicator.md +++ b/www/attributes/hx-indicator.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - kt-indicator +title: </> htmx - hx-indicator --- -## `kt-indicator` +## `hx-indicator` -The `kt-indicator` attribute allows you to specify the element that will have the `kutty-request` class +The `hx-indicator` attribute allows you to specify the element that will have the `htmx-request` class added to it for the duration of the request. This can be used to show spinners or progress indicators while the request is in flight. @@ -15,26 +15,26 @@ Here is an example with a spinner adjacent to the button: ```html <div> - <button kt-post="/example" kt-indicator="#spinner"> + <button hx-post="/example" hx-indicator="#spinner"> Post It! </button> - <img id="spinner" class="kutty-indicator" src="/img/bars.svg"/> + <img id="spinner" class="htmx-indicator" src="/img/bars.svg"/> </div> ``` -When a request is in flight, this will cause the `kutty-request` class to be added to the `#spinner` -image. The image also has the `kutty-indicator` class on it, which defines an opacity transition +When a request is in flight, this will cause the `htmx-request` class to be added to the `#spinner` +image. The image also has the `htmx-indicator` class on it, which defines an opacity transition that will show the spinner: ```css - .kutty-indicator{ + .htmx-indicator{ opacity:0; transition: opacity 500ms ease-in; } - .kutty-request .kutty-indicator{ + .htmx-request .htmx-indicator{ opacity:1 } - .kutty-request.kutty-indicator{ + .htmx-request.htmx-indicator{ opacity:1 } ``` @@ -43,13 +43,13 @@ If you would prefer a different effect for showing the spinner you could define CSS. Here is an example that uses `display` rather than opacity: ```css - .kutty-indicator{ + .htmx-indicator{ display:none; } - .kutty-request .my-indicator{ + .htmx-request .my-indicator{ display:inline; } - .kutty-request.my-indicator{ + .htmx-request.my-indicator{ display:inline; } ``` @@ -57,14 +57,14 @@ CSS. Here is an example that uses `display` rather than opacity: Note that the target of the `ic-indicator` selector need not be the exact element that you want to show: it can be any element in the parent hierarchy of the indicator. -Finally, note that the `kutty-request` class by default is added to the element causing +Finally, note that the `htmx-request` class by default is added to the element causing the request, so you can place an indicator inside of that element and not need to explictly call it out with the `ic-indicator` attribute: ```html -<button kt-post="/example"> +<button hx-post="/example"> Post It! - <img class="kutty-indicator" src="/img/bars.svg"/> + <img class="htmx-indicator" src="/img/bars.svg"/> </button> ``` @@ -72,13 +72,13 @@ call it out with the `ic-indicator` attribute: This simulates what a spinner might look like in that situation: -<button class="btn" kt-classes="toggle kutty-request:3s"> +<button class="btn" hx-classes="toggle htmx-request:3s"> Post It! - <img class="kutty-indicator" src="/img/bars.svg"/> + <img class="htmx-indicator" src="/img/bars.svg"/> </button> ### Notes -* `kt-indicator` is inherited and can be placed on a parent element -* In the absence of an explicit indicator, the `kutty-request` class will be added to the element triggering the +* `hx-indicator` is inherited and can be placed on a parent element +* In the absence of an explicit indicator, the `htmx-request` class will be added to the element triggering the request
\ No newline at end of file diff --git a/www/attributes/kt-params.md b/www/attributes/hx-params.md index b2d0f3f6..131d11a3 100644 --- a/www/attributes/kt-params.md +++ b/www/attributes/hx-params.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - kt-params +title: </> htmx - hx-params --- -## `kt-params` +## `hx-params` -The `kt-params` attribute allows you to filter the parameters that will be submitted with an AJAX request. +The `hx-params` attribute allows you to filter the parameters that will be submitted with an AJAX request. The possible values of this attribute are: @@ -15,7 +15,7 @@ The possible values of this attribute are: * `<param-list>` - Include all the comma separated list of parameter names ```html - <div kt-get="/example" kt-params="*">Get Some HTML, Including Params</div> + <div hx-get="/example" hx-params="*">Get Some HTML, Including Params</div> ``` This div will include all the parameters that a `POST` would, but they will be URL encoded @@ -23,4 +23,4 @@ and included in the URL, as per usual with a `GET`. ### Notes -* `kt-params` is inherited and can be placed on a parent element +* `hx-params` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-patch.md b/www/attributes/hx-patch.md index 7f59ddc1..6ece3541 100644 --- a/www/attributes/kt-patch.md +++ b/www/attributes/hx-patch.md @@ -1,15 +1,15 @@ --- layout: layout.njk -title: </> kutty - kt-patch +title: </> htmx - hx-patch --- -## `kt-patch` +## `hx-patch` -The `kt-patch` attribute will cause an element to issue a `PATCH` to the specified URL and swap +The `hx-patch` attribute will cause an element to issue a `PATCH` to the specified URL and swap the HTML into the DOM using a swap strategy: ```html -<button kt-patch="/account" kt-target="body"> +<button hx-patch="/account" hx-target="body"> Patch Your Account </button> ``` @@ -19,9 +19,9 @@ This example will cause the `button` to issue a `PATCH` to `/account` and swap t ### Notes -* `kt-patch` is not inherited +* `hx-patch` is not inherited * Since most browsers do not support issuing an actual `PATCH`, the request will actually be issued as a `POST`, with the [`X-HTTP-Method-Override`](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields) header set to `PATCH`. -* You can control the target of the swap using the [kt-target](/attributes/kt-target) attribute -* You can control the swap strategy by using the [kt-swap](/attributes/kt-swap) attribute -* You can control what event triggers the request with the [kt-trigger](/attributes/kt-trigger) attribute +* You can control the target of the swap using the [hx-target](/attributes/hx-target) attribute +* You can control the swap strategy by using the [hx-swap](/attributes/hx-swap) attribute +* You can control what event triggers the request with the [hx-trigger](/attributes/hx-trigger) attribute diff --git a/www/attributes/hx-post.md b/www/attributes/hx-post.md new file mode 100644 index 00000000..992f13a2 --- /dev/null +++ b/www/attributes/hx-post.md @@ -0,0 +1,25 @@ +--- +layout: layout.njk +title: </> htmx - hx-post +--- + +## `hx-post` + +The `hx-post` attribute will cause an element to issue a `POST` to the specified URL and swap +the HTML into the DOM using a swap strategy: + +```html +<button hx-post="/account/enable" hx-target="body"> + Enable Your Account +</button> +``` + +This example will cause the `button` to issue a `POST` to `/account/enable` and swap the returned HTML into + the `innerHTML` of the `body`. + +### Notes + +* `hx-post` is not inherited +* You can control the target of the swap using the [hx-target](/attributes/hx-target) attribute +* You can control the swap strategy by using the [hx-swap](/attributes/hx-swap) attribute +* You can control what event triggers the request with the [hx-trigger](/attributes/hx-trigger) attribute diff --git a/www/attributes/hx-prompt.md b/www/attributes/hx-prompt.md new file mode 100644 index 00000000..ea2d1ff6 --- /dev/null +++ b/www/attributes/hx-prompt.md @@ -0,0 +1,21 @@ +--- +layout: layout.njk +title: </> htmx - hx-prompt +--- + +## `hx-prompt` + +The `hx-prompt` attribute allows you to show a prompt before issuing a request. The value of +the prompt will be included in the requst in the `X-HX-Prompt` header. + +Here is an example: + +```html +<button hx-delete="/account" hx-prompt="Enter your account name to confirm deletion"> + Delete My Account +</button> +``` + +### Notes + +* `hx-prompt` is inherited and can be placed on a parent element diff --git a/www/attributes/hx-push-url.md b/www/attributes/hx-push-url.md new file mode 100644 index 00000000..674c1a62 --- /dev/null +++ b/www/attributes/hx-push-url.md @@ -0,0 +1,26 @@ +--- +layout: layout.njk +title: </> htmx - hx-push-url +--- + +## `hx-push-url` + +The `hx-push-url` attribute allows you to "push" a new entry into the browser location bar, which creates +a new history entry, allowing back-button and general history navigation. The possible values of this +attribute are `true` and `false`. + +Here is an example: + +```html +<div hx-get="/account" hx-push-url="true"> + Go to My Account +</div> +``` + +This will cause htmx to snapshot the current DOM to `localStorage` and push the URL `/account' into the browser +location bar. + +### Notes + +* `hx-push-url` is inherited and can be placed on a parent element +* see also the `X-HX-Push` response header diff --git a/www/attributes/kt-put.md b/www/attributes/hx-put.md index 6aa310f4..301980e3 100644 --- a/www/attributes/kt-put.md +++ b/www/attributes/hx-put.md @@ -1,15 +1,15 @@ --- layout: layout.njk -title: </> kutty - kt-put +title: </> htmx - hx-put --- -## `kt-put` +## `hx-put` -The `kt-put` attribute will cause an element to issue a `PUT` to the specified URL and swap +The `hx-put` attribute will cause an element to issue a `PUT` to the specified URL and swap the HTML into the DOM using a swap strategy: ```html -<button kt-put="/account" kt-target="body"> +<button hx-put="/account" hx-target="body"> Put Money In Your Account </button> ``` @@ -19,9 +19,9 @@ This example will cause the `button` to issue a `PUT` to `/account` and swap the ### Notes -* `kt-put` is not inherited +* `hx-put` is not inherited * Since most browsers do not support issuing an actual `PUT`, the request will actually be issued as a `POST`, with the [`X-HTTP-Method-Override`](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields) header set to `PUT`. -* You can control the target of the swap using the [kt-target](/attributes/kt-target) attribute -* You can control the swap strategy by using the [kt-swap](/attributes/kt-swap) attribute -* You can control what event triggers the request with the [kt-trigger](/attributes/kt-trigger) attribute +* You can control the target of the swap using the [hx-target](/attributes/hx-target) attribute +* You can control the swap strategy by using the [hx-swap](/attributes/hx-swap) attribute +* You can control what event triggers the request with the [hx-trigger](/attributes/hx-trigger) attribute diff --git a/www/attributes/kt-select.md b/www/attributes/hx-select.md index 8a81143c..268efc5e 100644 --- a/www/attributes/kt-select.md +++ b/www/attributes/hx-select.md @@ -1,18 +1,18 @@ --- layout: layout.njk -title: </> kutty - kt-select +title: </> htmx - hx-select --- -## `kt-select` +## `hx-select` -The `kt-select` attribute allows you to select the content you want swapped from a response. The value of +The `hx-select` attribute allows you to select the content you want swapped from a response. The value of this attribute is a CSS query selector of the element or elements to select from the response. Here is an example that selects a subset of the response content: ```html <div> - <button kt-get="/info" kt-select="#info-details" kt-swap="outerHTML"> + <button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML"> Get Info! </button> </div> @@ -23,4 +23,4 @@ which will replace the entire button in the DOM. ### Notes -* `kt-select` is inherited and can be placed on a parent element +* `hx-select` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-sse-src.md b/www/attributes/hx-sse-src.md index 661e90b6..3f2eec5d 100644 --- a/www/attributes/kt-sse-src.md +++ b/www/attributes/hx-sse-src.md @@ -1,16 +1,16 @@ --- layout: layout.njk -title: </> kutty - kt-sse-src +title: </> htmx - hx-sse-src --- -## `kt-sse-src` +## `hx-sse-src` -The `kt-sse-src` attribute establishes a [Server Sent Event](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) +The `hx-sse-src` attribute establishes a [Server Sent Event](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) `EventSource`, allowing children of the element to register for server sent event triggers. ```html - <div kt-sse-src="/event_stream"> - <div kt-get="/chatroom" kt-trigger="sse:chatter"> + <div hx-sse-src="/event_stream"> + <div hx-get="/chatroom" hx-trigger="sse:chatter"> ... </div> </div> @@ -21,4 +21,4 @@ a `GET` to the `/chatroom` url whenever the `chatter` event is seen. ### Notes -* `kt-sse-src` is not inherited +* `hx-sse-src` is not inherited diff --git a/www/attributes/kt-swap-oob.md b/www/attributes/hx-swap-oob.md index c772a23d..f5c7e4bc 100644 --- a/www/attributes/kt-swap-oob.md +++ b/www/attributes/hx-swap-oob.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - kt-swap-oob +title: </> htmx - hx-swap-oob --- -## `kt-swap-oob` +## `hx-swap-oob` -The `kt-swap-oob` attribute allows you specify that some content in a response should be swapped into +The `hx-swap-oob` attribute allows you specify that some content in a response should be swapped into the DOM somewhere other than the target, that is "Out of Band". This allows you to piggy back updates to other element updates on a response. @@ -15,7 +15,7 @@ Consider the following response HTML: <div> ... </div> -<div id="alerts" kt-swap-oob="true"> +<div id="alerts" hx-swap-oob="true"> Saved! </div> @@ -26,5 +26,5 @@ as a replacement for the element with the id `alerts`, and will not end up in th ### Notes -* `kt-swap-oob` is not inherited -* `kt-swap-oob` is only supported on top level elements in the response, not children +* `hx-swap-oob` is not inherited +* `hx-swap-oob` is only supported on top level elements in the response, not children diff --git a/www/attributes/kt-swap.md b/www/attributes/hx-swap.md index 577742f2..42f46e5d 100644 --- a/www/attributes/kt-swap.md +++ b/www/attributes/hx-swap.md @@ -1,12 +1,12 @@ --- layout: layout.njk -title: </> kutty - kt-swap +title: </> htmx - hx-swap --- -## `kt-swap` +## `hx-swap` -The `kt-swap` attribute allows you to specify how the response will be swapped in relative to the -[target](/attributes/kt-target) of an AJAX request. +The `hx-swap` attribute allows you to specify how the response will be swapped in relative to the +[target](/attributes/hx-target) of an AJAX request. The possible values of this attribute are: @@ -24,17 +24,17 @@ specification. So in this code: ```html - <div kt-get="/example" kt-swap="afterend">Get Some HTML & Append It</div> + <div hx-get="/example" hx-swap="afterend">Get Some HTML & Append It</div> ``` The `div` will issue a request to `/example` and append the returned content after the `div` -You can modify the amount of time that kutty will wait after receiving a response to swap the content +You can modify the amount of time that htmx will wait after receiving a response to swap the content by including a `swap` modifier: ```html <!-- this will wait 1s before doing the swap after it is received --> - <div kt-get="/example" kt-swap="innerHTML swap:1s">Get Some HTML & Append It</div> + <div hx-get="/example" hx-swap="innerHTML swap:1s">Get Some HTML & Append It</div> ``` Similarly, you can modify the time between the swap and the settle logic by including a `settle` @@ -42,14 +42,14 @@ modifier: ```html <!-- this will wait 1s before doing the swap after it is received --> - <div kt-get="/example" kt-swap="innerHTML settle:1s">Get Some HTML & Append It</div> + <div hx-get="/example" hx-swap="innerHTML settle:1s">Get Some HTML & Append It</div> ``` -These attributes can be used to synchronize kutty with the timing of CSS transition effects. +These attributes can be used to synchronize htmx with the timing of CSS transition effects. ### Notes -* `kt-swap` is inherited and can be placed on a parent element +* `hx-swap` is inherited and can be placed on a parent element * The default value of this attribute is `innerHTML` * The default swap delay is 0ms * The default settle delay is 100ms diff --git a/www/attributes/kt-target.md b/www/attributes/hx-target.md index fcd83e5f..2fd409d3 100644 --- a/www/attributes/kt-target.md +++ b/www/attributes/hx-target.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - kt-target +title: </> htmx - hx-target --- -## `kt-target` +## `hx-target` -The `kt-target` attribute allows you to target a different element for swapping than the one issuing the AJAX +The `hx-target` attribute allows you to target a different element for swapping than the one issuing the AJAX request. The value of this attribute can be: * a CSS query selector of the element to target @@ -18,7 +18,7 @@ Here is an example that targets a div: ```html <div> <div id="response-div"></div> - <button kt-post="/register" kt-target="#response-div" kt-swap="beforeEnd"> + <button hx-post="/register" hx-target="#response-div" hx-swap="beforeEnd"> Register! </button> </div> @@ -28,4 +28,4 @@ The response from the `/register` url will be appended to the `div` with the id ### Notes -* `kt-target` is inherited and can be placed on a parent element +* `hx-target` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-trigger.md b/www/attributes/hx-trigger.md index 4ccb3093..35c0d63e 100644 --- a/www/attributes/kt-trigger.md +++ b/www/attributes/hx-trigger.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - kt-trigger +title: </> htmx - hx-trigger --- -## `kt-trigger` +## `hx-trigger` -The `kt-trigger` attribute allows you to specify what triggers an AJAX request. A trigger +The `hx-trigger` attribute allows you to specify what triggers an AJAX request. A trigger value can be one of the following: * An event name (e.g. "click") followed by a set of event modifiers @@ -17,7 +17,7 @@ value can be one of the following: A standard event, such as `click` can be specified as the trigger like so: ```html -<div kt-get="/clicked" kt-trigger="click">Click Me</div> +<div hx-get="/clicked" hx-trigger="click">Click Me</div> ``` Standard events can also have modifiers that change how they behave. The modifiers are: @@ -32,13 +32,13 @@ and the user hasn't typed anything new for 1 second: ```html <input name="q" - kt-get="/search" kt-trigger="keyup changed delay:1s" - kt-target="#search-results"/> + hx-get="/search" hx-trigger="keyup changed delay:1s" + hx-target="#search-results"/> ``` The response from the `/register` url will be appended to the `div` with the id `response-div`. -There are two special events that are non-standard that kutty supports: +There are two special events that are non-standard that htmx supports: * `load` - triggered on load (useful for lazy-loading something) * `reveal` - triggered when an element is scrolled into the viewport (also useful for lazy-loading) @@ -48,7 +48,7 @@ There are two special events that are non-standard that kutty supports: By using the syntax `every <timing declaration>` you can have an element poll periodically: ```html -<div kt-get="/latest_updates" kt-trigger="every 1s"> +<div hx-get="/latest_updates" hx-trigger="every 1s"> Nothing Yet! </div> ``` @@ -64,8 +64,8 @@ an element can register to be triggered by a specific SSE event using the syntax Here is an example: ```html - <div kt-sse-src="/event_stream"> - <div kt-get="/chatroom" kt-trigger="sse:chatter"> + <div hx-sse-src="/event_stream"> + <div hx-get="/chatroom" hx-trigger="sse:chatter"> ... </div> </div> @@ -76,4 +76,4 @@ a `GET` to the `/chatroom` url whenever the `chatter` event is seen. ### Notes -* `kt-trigger` is not inherited
\ No newline at end of file +* `hx-trigger` is not inherited
\ No newline at end of file diff --git a/www/attributes/kt-error-url.md b/www/attributes/kt-error-url.md deleted file mode 100644 index 58f8f7d1..00000000 --- a/www/attributes/kt-error-url.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -layout: layout.njk -title: </> kutty - kt-error-url ---- - -## `kt-error-url` - -The `kt-error-url` attribute allows you to send client-side errors to a specified URL. It is typically put on the -body tag, so all errors are caught and send to the server. - -```html -<body kt-error-url="/errors">\ - -</body> -``` -When a client side error is caught by kutty it will be `POST`-ed to the given URL, with the following JSON format: - -```json - { "elt": elt.id, "event": eventName, "detail" : detail } -``` - -### Notes - -* `kt-error-url` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-get.md b/www/attributes/kt-get.md deleted file mode 100644 index e2f5c65c..00000000 --- a/www/attributes/kt-get.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: layout.njk -title: </> kutty - kt-get ---- - -## `kt-get` - -The `kt-get` attribute will cause an element to issue a `GET` to the specified URL and swap -the HTML into the DOM using a swap strategy: - -```html - <div kt-get="/example">Get Some HTML</div> -``` - -This example will cause the `div` to issue a `GET` to `/example` and swap the returned HTML into - the `innerHTML` of the `div`. - -### Notes - -* `kt-get` is not inherited -* By default `kt-get` does not include any parameters. You can use the [kt-params](/attributes/kt-params) - attribute to change this -* You can control the target of the swap using the [kt-target](/attributes/kt-target) attribute -* You can control the swap strategy by using the [kt-swap](/attributes/kt-swap) attribute -* You can control what event triggers the request with the [kt-trigger](/attributes/kt-trigger) attribute diff --git a/www/attributes/kt-post.md b/www/attributes/kt-post.md deleted file mode 100644 index 6a4d06ef..00000000 --- a/www/attributes/kt-post.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: layout.njk -title: </> kutty - kt-post ---- - -## `kt-post` - -The `kt-post` attribute will cause an element to issue a `POST` to the specified URL and swap -the HTML into the DOM using a swap strategy: - -```html -<button kt-post="/account/enable" kt-target="body"> - Enable Your Account -</button> -``` - -This example will cause the `button` to issue a `POST` to `/account/enable` and swap the returned HTML into - the `innerHTML` of the `body`. - -### Notes - -* `kt-post` is not inherited -* You can control the target of the swap using the [kt-target](/attributes/kt-target) attribute -* You can control the swap strategy by using the [kt-swap](/attributes/kt-swap) attribute -* You can control what event triggers the request with the [kt-trigger](/attributes/kt-trigger) attribute diff --git a/www/attributes/kt-prompt.md b/www/attributes/kt-prompt.md deleted file mode 100644 index cce04cfd..00000000 --- a/www/attributes/kt-prompt.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -layout: layout.njk -title: </> kutty - kt-prompt ---- - -## `kt-prompt` - -The `kt-prompt` attribute allows you to show a prompt before issuing a request. The value of -the prompt will be included in the requst in the `X-KT-Prompt` header. - -Here is an example: - -```html -<button kt-delete="/account" kt-prompt="Enter your account name to confirm deletion"> - Delete My Account -</button> -``` - -### Notes - -* `kt-prompt` is inherited and can be placed on a parent element diff --git a/www/attributes/kt-push-url.md b/www/attributes/kt-push-url.md deleted file mode 100644 index 03d3a047..00000000 --- a/www/attributes/kt-push-url.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: layout.njk -title: </> kutty - kt-push-url ---- - -## `kt-push-url` - -The `kt-push-url` attribute allows you to "push" a new entry into the browser location bar, which creates -a new history entry, allowing back-button and general history navigation. The possible values of this -attribute are `true` and `false`. - -Here is an example: - -```html -<div kt-get="/account" kt-push-url="true"> - Go to My Account -</div> -``` - -This will cause kutty to snapshot the current DOM to `localStorage` and push the URL `/account' into the browser -location bar. - -### Notes - -* `kt-push-url` is inherited and can be placed on a parent element -* see also the `X-KT-Push` response header diff --git a/www/css/prism-kutty.css b/www/css/prism-htmx.css index fffdcf6f..ce47b054 100644 --- a/www/css/prism-kutty.css +++ b/www/css/prism-htmx.css @@ -1,5 +1,5 @@ /** - * kutty theme for JavaScript, CSS and HTML + * htmx theme for JavaScript, CSS and HTML * based on okaidia theme by ocodia */ diff --git a/www/docs.md b/www/docs.md index 2b4758f7..22236376 100644 --- a/www/docs.md +++ b/www/docs.md @@ -1,6 +1,6 @@ --- layout: layout.njk -title: </> kutty - high power tools for html +title: </> htmx - high power tools for html --- <div class="row"> <div class="2 col nav"> @@ -32,12 +32,12 @@ title: </> kutty - high power tools for html </div> <div class="10 col"> -## <a name="introduction"></a>[Kutty in a Nutshell](#introduction) +## <a name="introduction"></a>[Htmx in a Nutshell](#introduction) -Kutty is a library that allows you to access modern browser features directly from HTML, rather than using +Htmx is a library that allows you to access modern browser features directly from HTML, rather than using javascript. -To understand kutty, first lets take a look at an anchor tag: +To understand htmx, first lets take a look at an anchor tag: ``` html <a href="/blog">Blog</a> @@ -51,20 +51,20 @@ This anchor tag tells a browser: With that in mind, consider the following bit of HTML: ``` html - <div kt-post="/clicked" - kt-trigger="click" - kt-target="#parent-div" - kt-swap="outerHTML"> + <div hx-post="/clicked" + hx-trigger="click" + hx-target="#parent-div" + hx-swap="outerHTML"> Click Me! </div> ``` -This tells kutty: +This tells htmx: > "When a user clicks on this div, issue an HTTP POST request to '/clicked' and use the content from the response > to replace the element with the id `parent-div` in the DOM" -Kutty extends and generalizes the core idea of HTML as a hypertext, opening up many more possibilities directly +Htmx extends and generalizes the core idea of HTML as a hypertext, opening up many more possibilities directly within the language: * Now any element, not just anchors and forms, can issue an HTTP request @@ -72,37 +72,37 @@ within the language: * Now any [HTTP verb](https://en.wikipedia.org/wiki/HTTP_Verbs), not just `GET` and `POST`, can be used * Now any element, not just the entire window, can be the target for update by the request -Note that when you are using kutty, on the server side you respond with *HTML*, not *JSON*. This keeps you firmly +Note that when you are using htmx, on the server side you respond with *HTML*, not *JSON*. This keeps you firmly within the [original web programming model]((https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)), using [Hypertext As The Engine Of Application State](https://en.wikipedia.org/wiki/HATEOAS) without even needing to really understand that concept. -It's worth mentioning that, if you prefer, you can use the `data-` prefix when using kutty: +It's worth mentioning that, if you prefer, you can use the `data-` prefix when using htmx: ``` html - <a data-kt-post="/click">Click Me!</a> + <a data-hx-post="/click">Click Me!</a> ``` ## <a name="installing"></a> [Installing](#installing) -Kutty is a dependency-free javascript library. +Htmx is a dependency-free javascript library. -It can be used via [NPM](https://www.npmjs.com/) as "`kutty.org`" or downloaded or included from -[unpkg](https://unpkg.com/browse/kutty.org/) or your other favorite NPM-based CDN: +It can be used via [NPM](https://www.npmjs.com/) as "`htmx.org`" or downloaded or included from +[unpkg](https://unpkg.com/browse/htmx.org/) or your other favorite NPM-based CDN: ``` html - <script src="https://unpkg.com/kutty.org@0.0.2"></script> + <script src="https://unpkg.com/htmx.org@0.0.2"></script> ``` ## <a name="ajax"></a> [AJAX](#ajax) -The core feature of kutty is a set of attributes that allow you to issue AJAX requests directly from HTML: +The core feature of htmx is a set of attributes that allow you to issue AJAX requests directly from HTML: -* [kt-get](/attributes/kt-get) - Issues a `GET` request to the given URL -* [kt-post](/attributes/kt-post) - Issues a `POST` request to the given URL -* [kt-put](/attributes/kt-put) - Issues a `PUT` request to the given URL -* [kt-patch](/attributes/kt-patch) - Issues a `PATCH` request to the given URL -* [kt-delete](/attributes/kt-delete) - Issues a `DELETE` request to the given URL +* [hx-get](/attributes/hx-get) - Issues a `GET` request to the given URL +* [hx-post](/attributes/hx-post) - Issues a `POST` request to the given URL +* [hx-put](/attributes/hx-put) - Issues a `PUT` request to the given URL +* [hx-patch](/attributes/hx-patch) - Issues a `PATCH` request to the given URL +* [hx-delete](/attributes/hx-delete) - Issues a `DELETE` request to the given URL (Since most browsers only support issuing `GET` and `POST`, a request with one of the other three methods will actually be issued as a `POST`, with the `X-HTTP-Method-Override` header set to the desired method.) @@ -111,7 +111,7 @@ Each of these attributes takes a URL to issue an AJAX request to. The element w type to the given URL when the element is [triggered](#triggers): ```html - <div kt-put="/messages"> + <div hx-put="/messages"> Put To Messages </div> ``` @@ -128,13 +128,13 @@ By default, AJAX requests are triggered by the "natural" event of an element: * `form` is triggered on the `submit` event * everything else is triggered by the `click` event -If you want different behavior you can use the [kt-trigger](/attributes/kt-trigger) +If you want different behavior you can use the [hx-trigger](/attributes/hx-trigger) attribute to specify which event will cause the request. Here is a `div` that posts to `/mouse_entered` when a mouse enters it: ```html - <div kt-post="/mouse_entered" kt-trigger="mouseenter"> + <div hx-post="/mouse_entered" hx-trigger="mouseenter"> [Here Mouse, Mouse!] </div> ``` @@ -142,7 +142,7 @@ Here is a `div` that posts to `/mouse_entered` when a mouse enters it: If you want a request to only happen once, you can use the `once` modifier for the trigger: ```html - <div kt-post="/mouse_entered" kt-trigger="mouseenter once""> + <div hx-post="/mouse_entered" hx-trigger="mouseenter once""> [Here Mouse, Mouse!] </div> ``` @@ -157,9 +157,9 @@ You can use these two attributes to implement a common UX pattern, [Active Searc ```html <input type="text" name="q" - kt-get="/trigger_delay" - kt-trigger="keyup changed delay:500ms" - kt-target="#search-results" + hx-get="/trigger_delay" + hx-trigger="keyup changed delay:500ms" + hx-target="#search-results" placeholder="Search..."/> <div id="search-results"></div> ``` @@ -169,7 +169,7 @@ into the `div` with the id `search-results`. #### <a name="special-events"></a> [Special Events](#special-events) -kutty provides a few special events for use in [kt-trigger](/attributes/kt-trigger): +htmx provides a few special events for use in [hx-trigger](/attributes/hx-trigger): * `load` - fires once when the element is first loaded * `revealed` - fires once when an element first scrolls into the viewport @@ -179,14 +179,14 @@ You can also use custom events to trigger requests if you have an advanced use c #### <a name="polling"></a> [Polling](#polling) If you want an element to poll the given URL rather than wait for an event, you can use the `every` syntax -with the [`kt-trigger`](/attributes/kt-trigger/) attribute: +with the [`hx-trigger`](/attributes/hx-trigger/) attribute: ```html - <div kt-get="/news" trigger="every 2s"> + <div hx-get="/news" trigger="every 2s"> </div> ``` -This tells kutty +This tells htmx > Every 2 seconds, issue a GET to /news and load the response into the div @@ -195,13 +195,13 @@ and the element will cancel the polling. #### <a name="load_polling"></a> [Load Polling](#load_polling) -Another technique that can be used to achieve polling in kutty is "load polling", where an element specifies +Another technique that can be used to achieve polling in htmx is "load polling", where an element specifies an `load` trigger along with a delay, and replaces itself with the response: ```html -<div kt-get="/messages" - kt-trigger="load delay:1s" - kt-swap="outerHTML"> +<div hx-get="/messages" + hx-trigger="load delay:1s" + hx-swap="outerHTML"> </div> ``` @@ -218,9 +218,9 @@ when you are showing the user a [progress bar](/examples/progress-bar). a way for servers to send events to browsers. It provides a higher-level mechanism for communication between the server and the browser than websockets. -If you want an element to respond to a Server Sent Event via kutty, you need to do two things: +If you want an element to respond to a Server Sent Event via htmx, you need to do two things: -1. Define an SSE source. To do this, add a [kt-sse-src](/attributes/kt-sse-src) attribute on a parent element +1. Define an SSE source. To do this, add a [hx-sse-src](/attributes/hx-sse-src) attribute on a parent element that specifies the URL from which Server Sent Events will be received. 2. Specify the Server Sent Event that will trigger the element, with the prefix `sse:` @@ -228,8 +228,8 @@ that specifies the URL from which Server Sent Events will be received. Here is an example: ```html - <body kt-sse-src="/sse_messages"> - <div trigger="sse:new_news" kt-get="/news"></div> + <body hx-sse-src="/sse_messages"> + <div trigger="sse:new_news" hx-get="/news"></div> </body> ``` @@ -239,49 +239,49 @@ notify the div if there was new news to get, rather than the steady requests tha ### <a name="indicators"></a> [Request Indicators](#indicators) When an AJAX request is issued it is often good to let the user know that something is happening since the browser -will not give them any feedback. You can accomplish this in kutty by using `kutty-indicator` class. +will not give them any feedback. You can accomplish this in htmx by using `htmx-indicator` class. -The `kutty-indicator` class is defined so that the opacity of any element with this class is 0 by default, making it invisible +The `htmx-indicator` class is defined so that the opacity of any element with this class is 0 by default, making it invisible but present in the DOM. -When kutty issues a request, it will put a `kutty-request` class onto an element (either the requesting element or -another element, if specified). The `kutty-request` class will cause a child element with the `kutty-indicator` class +When htmx issues a request, it will put a `htmx-request` class onto an element (either the requesting element or +another element, if specified). The `htmx-request` class will cause a child element with the `htmx-indicator` class on it to transition to an opacity of 1, showing the indicator. ```html - <button kt-get="/click"> + <button hx-get="/click"> Click Me! - <img class="kutty-indicator" src="/spinner.gif"/> + <img class="htmx-indicator" src="/spinner.gif"/> </button> ``` -Here we have a button. When it is clicked the `kutty-request` class will be added to it, which will reveal the spinner +Here we have a button. When it is clicked the `htmx-request` class will be added to it, which will reveal the spinner gif element. (I like [SVG spinners](http://samherbert.net/svg-loaders/) these days.) -While the `kutty-indicator` class uses opacity to hide and show the progress indicator, if you would prefer another mechanism +While the `htmx-indicator` class uses opacity to hide and show the progress indicator, if you would prefer another mechanism you can create your own CSS transition like so: ```css - .kutty-indicator{ + .htmx-indicator{ display:none; } - .kutty-request .my-indicator{ + .htmx-request .my-indicator{ display:inline; } - .kutty-request.my-indicator{ + .htmx-request.my-indicator{ display:inline; } ``` -If you want the `kutty-request` class added to a different element, you can use the [kt-indicator](/attributes/kt-indicator) +If you want the `htmx-request` class added to a different element, you can use the [hx-indicator](/attributes/hx-indicator) attribute with a CSS selector to do so: ```html <div> - <button kt-get="/click" kt-indicator="#indicator"> + <button hx-get="/click" hx-indicator="#indicator"> Click Me! </button> - <img id="indicator" class="kutty-indicator" src="/spinner.gif"/> + <img id="indicator" class="htmx-indicator" src="/spinner.gif"/> </div> ``` @@ -291,13 +291,13 @@ and had the same effect. ### <a name="targets"></a> [Targets](#targets) If you want the response to be loaded into a different element other than the one that made the request, you can -use the [kt-target](/attributes/kt-target) attribute, which takes a CSS selector. Looking back at our Live Search example: +use the [hx-target](/attributes/hx-target) attribute, which takes a CSS selector. Looking back at our Live Search example: ```html <input type="text" name="q" - kt-get="/trigger_delay" - kt-trigger="keyup delay:500ms changed" - kt-target="#search-results" + hx-get="/trigger_delay" + hx-trigger="keyup delay:500ms changed" + hx-target="#search-results" placeholder="Search..."/> <div id="search-results"></div> ``` @@ -307,8 +307,8 @@ input tag. ### <a name="swapping"></a> [Swapping](#swapping) -kutty offers a few different ways to swap the HTML returned into the DOM. By default, the content replaces the -`innerHTML` of the target element. You can modify this by using the [kt-swap](/attributes/kt-swap) attribute +htmx offers a few different ways to swap the HTML returned into the DOM. By default, the content replaces the +`innerHTML` of the target element. You can modify this by using the [hx-swap](/attributes/hx-swap) attribute with any of the following values: * `innerHTML` - the default, puts the content inside the target element @@ -321,10 +321,10 @@ with any of the following values: #### <a name="oob_swaps"></a>[Out of Band Swaps](#oob_swaps) If you want to swap content from a response directly into the DOM by using the `id` attribute you can use the -[kt-swap-oob](/attributes/kt-swap-oob) attribute in the *response* html: +[hx-swap-oob](/attributes/hx-swap-oob) attribute in the *response* html: ```html - <div id="message" kt-swap-oob="true">Swap me directly!</div> + <div id="message" hx-swap-oob="true">Swap me directly!</div> Additional Content ``` @@ -337,7 +337,7 @@ Note that out of band elements must be in the top level of the response, and not #### Selecting Content To Swap -If you want to select a subset of the response HTML to swap into the target, you can use the [kt-select](/attributes/kt-select) +If you want to select a subset of the response HTML to swap into the target, you can use the [hx-select](/attributes/hx-select) attribute, which takes a CSS selector and selects the matching elements from the response. ### <a name="parameters"></a> [Parameters](#parameters) @@ -348,153 +348,153 @@ will include the values of all inputs within it. Additionally, if the element causes a non-`GET` request, the values of all the inputs of the nearest enclosing form will be included. -If you wish to include the values of other elements, you can use the [kt-include](/attributes/kt-include) attribute +If you wish to include the values of other elements, you can use the [hx-include](/attributes/hx-include) attribute with a CSS selector of all the elements whose values you want to include in the request. -If you wish to filter out some parameters you can use the [kt-params](/attributes/kt-params) attribute. +If you wish to filter out some parameters you can use the [hx-params](/attributes/hx-params) attribute. -Finally, if you want to programatically modify the parameters, you can use the [configRequest.kutty](/events#configRequest.kutty) +Finally, if you want to programatically modify the parameters, you can use the [configRequest.htmx](/events#configRequest.htmx) event. ## <a name="history"></a> [History Support](#history) -Kutty provides a simple mechanism for interacting with the [browser history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API): +Htmx provides a simple mechanism for interacting with the [browser history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API): If you want a given element to push its request URL into the browser navigation bar and add the current state of the page -to the browser's history, include the [kt-push](/attributes/kt-push) attribute: +to the browser's history, include the [hx-push](/attributes/hx-push) attribute: ```html - <a kt-get="/blog" kt-push="true">Blog</a> + <a hx-get="/blog" hx-push="true">Blog</a> ``` -When a user clicks on this link, kutty will snapshot the current DOM and store it before it makes a request to /blog. +When a user clicks on this link, htmx will snapshot the current DOM and store it before it makes a request to /blog. It then does the swap and pushes a new location onto the history stack. -When a user hits the back button, kutty will retrieve the old content from storage and swap it back into the target, +When a user hits the back button, htmx will retrieve the old content from storage and swap it back into the target, simulating "going back" to the previous state. ### Specifying History Snapshot Element -By default, kutty will use the `body` to take and restore the history snapshop from. This is usually the right thing, but -if you want to use a narrower element for snapshotting you can use the [kt-history-element](/attributes/kt-history-element) +By default, htmx will use the `body` to take and restore the history snapshop from. This is usually the right thing, but +if you want to use a narrower element for snapshotting you can use the [hx-history-element](/attributes/hx-history-element) attribute to specify a different one. Careful: this element will need to be on all pages or restoring from history won't work reliably. ## <a name="requests">[Requests & Responses](#requests) -Kutty expects responses to the AJAX requests it makes to be HTML, typically HTML fragments (although a full HTML -document, matched with a [kt-select](/attributes/kt-select) tag can be useful too). Kutty will then swap the returned +Htmx expects responses to the AJAX requests it makes to be HTML, typically HTML fragments (although a full HTML +document, matched with a [hx-select](/attributes/hx-select) tag can be useful too). Htmx will then swap the returned HTML into the document at the target specified and with the swap strategy specified. Sometimes you might want to do nothing in the swap, but still perhaps trigger a client side event ([see below](#response-headers)). -For this situation you can return a `204 - No Content` response code, and kutty will ignore the content of the response. +For this situation you can return a `204 - No Content` response code, and htmx will ignore the content of the response. -In the event of an error response from the server (e.g. a 404 or a 501), kutty will trigger the [`responseError.kutty`](/events#responseError.kutty) +In the event of an error response from the server (e.g. a 404 or a 501), htmx will trigger the [`responseError.htmx`](/events#responseError.htmx) event, which you can handle. -In the event of a connection error, the `sendError.kutty` event will be triggered. +In the event of a connection error, the `sendError.htmx` event will be triggered. ### <a name="request-header"></a> [Request Headers](#request-headers) -kutty includes a number of useful headers in requests: - -* `X-KT-Request` - will be set to "true" -* `X-KT-Trigger` - will be set to the id of the element that triggered the request -* `X-KT-Trigger-Name` - will be set to the name of the element that triggered the request -* `X-KT-Target` - will be set to the id of the target element -* `X-KT-Current-URL` - will be set to the URL of the browser -* `X-KT-Prompt` - will be set to the value entered by the user when prompted via [kt-prompt](/attributes/kt-prompt) -* `X-KT-Event-Target` - the id of the original target of the event that triggered the request -* `X-KT-Active-Element` - the id of the current active element -* `X-KT-Active-Element-Name` - the name of the current active element -* `X-KT-Active-Element-Value` - the value of the current active element +htmx includes a number of useful headers in requests: + +* `X-HX-Request` - will be set to "true" +* `X-HX-Trigger` - will be set to the id of the element that triggered the request +* `X-HX-Trigger-Name` - will be set to the name of the element that triggered the request +* `X-HX-Target` - will be set to the id of the target element +* `X-HX-Current-URL` - will be set to the URL of the browser +* `X-HX-Prompt` - will be set to the value entered by the user when prompted via [hx-prompt](/attributes/hx-prompt) +* `X-HX-Event-Target` - the id of the original target of the event that triggered the request +* `X-HX-Active-Element` - the id of the current active element +* `X-HX-Active-Element-Name` - the name of the current active element +* `X-HX-Active-Element-Value` - the value of the current active element * `X-HTTP-Method-Override` - the HTTP verb for non-`GET` and `POST` requests ### <a name="response-header"></a> [Response Headers](#response-headers) -kutty supports two special response headers: +htmx supports two special response headers: -* `X-KT-Trigger` - can be used to trigger client side events, see the [documentation](/headers/x-kt-trigger) for examples. -* `X-KT-Push` - can be used to push a new URL into the browsers address bar +* `X-HX-Trigger` - can be used to trigger client side events, see the [documentation](/headers/x-hx-trigger) for examples. +* `X-HX-Push` - can be used to push a new URL into the browsers address bar ### Request Order of Operations -The order of operations in a kutty request are: +The order of operations in a htmx request are: * The element is triggered and begins a request * Values are gathered for the request - * The `kutty-request` class is applied to the appropriate elements + * The `htmx-request` class is applied to the appropriate elements * The request is then issued asynchronously via AJAX - * Upon getting a response the target element is marked with the `kutty-swapping` class - * An optional swap delay is applied (see the [kt-swap-delay](/attributes/kt-swap-delay) attribute) + * Upon getting a response the target element is marked with the `htmx-swapping` class + * An optional swap delay is applied (see the [hx-swap-delay](/attributes/hx-swap-delay) attribute) * The actual content swap is done - * the `kutty-swapping` class is removed from the target - * the `kutty-settling` class is applied to the target + * the `htmx-swapping` class is removed from the target + * the `htmx-settling` class is applied to the target * A settle delay is done (default: 100ms) * The DOM is settled - * the `kutty-settling` class is removed from the target + * the `htmx-settling` class is removed from the target -You can use the `kutty-swapping` and `kutty-settling` classes to create +You can use the `htmx-swapping` and `htmx-settling` classes to create [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions) between pages. ## Miscellaneous Attributes -In addition to the core AJAX functionality, kutty also has a few other tricks up its sleeve that help you build +In addition to the core AJAX functionality, htmx also has a few other tricks up its sleeve that help you build nice interfaces without javascript. ### Class Swapping -Kutty supports an attribute, [kt-classes](/attributes/kt-classes) that allows you to add, remove and toggle classes after +Htmx supports an attribute, [hx-classes](/attributes/hx-classes) that allows you to add, remove and toggle classes after a delay. This can be used to create CSS transition effects. Here are some examples: ```html <!-- adds the class "foo" after 100ms --> -<div kt-classes="add foo"/> +<div hx-classes="add foo"/> <!-- removes the class "bar" after 1s --> -<div kt-classes="remove bar:1s"/> +<div hx-classes="remove bar:1s"/> <!-- removes the class "bar" after 1s then adds the class "foo" 1s after that --> -<div kt-classes="remove bar:1s, add foo:1s"/> +<div hx-classes="remove bar:1s, add foo:1s"/> <!-- removes the class "bar" and adds class "foo" after 1s --> -<div kt-classes="remove bar:1s & add foo:1s"/> +<div hx-classes="remove bar:1s & add foo:1s"/> <!-- toggles the class "foo" every 1s --> -<div kt-classes="toggle foo:1s"/> +<div hx-classes="toggle foo:1s"/> ``` -Full documentation is available [on the documentation page.](/attributes/kt-classes) +Full documentation is available [on the documentation page.](/attributes/hx-classes) ### Boosting -Kutty supports "boosting" regular HTML anchors and forms with the [kt-boost](/attributes/kt-boost) attribute. This +Htmx supports "boosting" regular HTML anchors and forms with the [hx-boost](/attributes/hx-boost) attribute. This attribute will convert all anchor tags and forms into AJAX requests that, by default, target the body of the page. This functionality is somewhat similar to [Turbolinks](https://github.com/turbolinks/turbolinks). ## <a name="events"></a> [Events & Logging](#events) -Kutty has an extensive events mechanism, which doubles as the logging system. +Htmx has an extensive events mechanism, which doubles as the logging system. -If you want to register for a given kutty event you can use the following javascript: +If you want to register for a given htmx event you can use the following javascript: ```javascript - kutty.on("load.kutty", function(evt) { + htmx.on("load.htmx", function(evt) { myJavascriptLib.init(evt.details.elt); }); ``` -This event is fired every time an element is loaded into the DOM by kutty, and is effectively the load event. In +This event is fired every time an element is loaded into the DOM by htmx, and is effectively the load event. In fact this is so common, you can use the helper function: ```javascript - kutty.onLoad(function(target) { + htmx.onLoad(function(target) { myJavascriptLib.init(target); }); ``` @@ -504,46 +504,46 @@ The full set of events can be seen [on the reference page](/reference#events). ### Logging -If you set a logger at `kutty.logger`, every event will be logged. This can be very useful for troubleshooting: +If you set a logger at `htmx.logger`, every event will be logged. This can be very useful for troubleshooting: ```javascript - kutty.logger = function(elt, event, data) { + htmx.logger = function(elt, event, data) { if(console) { console.log(event, elt, data); } } ``` -Kutty can also send errors to a URL that is specified with the [kt-error-url](/attributes/kt-error-url) attributes. This can be useful for debugging client-side issues. +Htmx can also send errors to a URL that is specified with the [hx-error-url](/attributes/hx-error-url) attributes. This can be useful for debugging client-side issues. -Kutty includes a helper method: +Htmx includes a helper method: ```javascript - kutty.logAll(); + htmx.logAll(); ``` if you want to log everything while developing. -## <a name="config"></a>[Configuring kutty](#config) +## <a name="config"></a>[Configuring htmx](#config) -Kutty allows you to configure a few defaults: +Htmx allows you to configure a few defaults: -* `kutty.config.historyEnabled` - defaults to `true`, really only useful for testing -* `kutty.config.historyCacheSize` - defaults to 10 -* `kutty.config.defaultSwapStyle` - defaults to `innerHTML` -* `kutty.config.defaultSwapDelay` - defaults to 0 -* `kutty.config.defaultSettleDelay` - defaults to 100 -* `kutty.config.includeIndicatorStyles` - defaults to `true` (determines if the `kutty-indicator` default styles are loaded, must be set in a `meta` tag before the kutty js is included) +* `htmx.config.historyEnabled` - defaults to `true`, really only useful for testing +* `htmx.config.historyCacheSize` - defaults to 10 +* `htmx.config.defaultSwapStyle` - defaults to `innerHTML` +* `htmx.config.defaultSwapDelay` - defaults to 0 +* `htmx.config.defaultSettleDelay` - defaults to 100 +* `htmx.config.includeIndicatorStyles` - defaults to `true` (determines if the `htmx-indicator` default styles are loaded, must be set in a `meta` tag before the htmx js is included) You can set them directly in javascript, or you can use a `meta` tag: ```html - <meta name="kutty-config" content='{"defaultSwapStyle":"outerHTML"}'> + <meta name="htmx-config" content='{"defaultSwapStyle":"outerHTML"}'> ``` ### Conclusion -And that's it! Have fun with kutty: you can accomplish [quite a bit](/examples) without a lot of code. +And that's it! Have fun with htmx: you can accomplish [quite a bit](/examples) without a lot of code. </div> </div> diff --git a/www/events.md b/www/events.md index 0af9bb54..3f3a31ef 100644 --- a/www/events.md +++ b/www/events.md @@ -1,14 +1,14 @@ --- layout: layout.njk -title: </> kutty - high power tools for html +title: </> htmx - high power tools for html --- ## Events -Kutty provides an extensive events system that can be used to modify and enhance behavior. Events +Htmx provides an extensive events system that can be used to modify and enhance behavior. Events are listed below. -### <a name="afterOnLoad.kutty"></a> Event - [`afterOnLoad.kutty`](#afterOnLoad.kutty) +### <a name="afterOnLoad.htmx"></a> Event - [`afterOnLoad.htmx`](#afterOnLoad.htmx) This event is triggered after an AJAX `onload` has finished. Note that this does not mean that the content has been swapped or settled yet, only that the request has finished. @@ -19,7 +19,7 @@ has been swapped or settled yet, only that the request has finished. * `detail.xhr` - the `XMLHttpRequest` * `detail.target` - the target of the request -### <a name="afterSettle.kutty"></a> Event - [`afterSettle.kutty`](#afterSettle.kutty) +### <a name="afterSettle.htmx"></a> Event - [`afterSettle.htmx`](#afterSettle.htmx) This event is triggered after the DOM has [settled](/docs#settling). @@ -29,7 +29,7 @@ This event is triggered after the DOM has [settled](/docs#settling). * `detail.xhr` - the `XMLHttpRequest` * `detail.target` - the target of the request -### <a name="afterSwap.kutty"></a> Event - [`afterSwap.kutty`](#afterSwap.kutty) +### <a name="afterSwap.htmx"></a> Event - [`afterSwap.htmx`](#afterSwap.htmx) This event is triggered after new content has been [swapped into the DOM](/docs#swapping). @@ -39,7 +39,7 @@ This event is triggered after new content has been [swapped into the DOM](/docs * `detail.xhr` - the `XMLHttpRequest` * `detail.target` - the target of the request -### <a name="beforeOnLoad.kutty"></a> Event - [`beforeOnLoad.kutty`](#beforeOnLoad.kutty) +### <a name="beforeOnLoad.htmx"></a> Event - [`beforeOnLoad.htmx`](#beforeOnLoad.htmx) This event is triggered before any new content has been [swapped into the DOM](/docs#swapping). If the event is cancelled, no swap will occur. @@ -50,7 +50,7 @@ the event is cancelled, no swap will occur. * `detail.xhr` - the `XMLHttpRequest` * `detail.target` - the target of the request -### <a name="beforeRequest.kutty"></a> Event - [`beforeRequest.kutty`](#beforeRequest.kutty) +### <a name="beforeRequest.htmx"></a> Event - [`beforeRequest.htmx`](#beforeRequest.htmx) This event is triggered before an AJAX request is issued. If the event is cancelled, no request will occur. @@ -60,7 +60,7 @@ This event is triggered before an AJAX request is issued. If the event is cance * `detail.xhr` - the `XMLHttpRequest` * `detail.target` - the target of the request -### <a name="historyCacheMiss.kutty"></a> Event - [`historyCacheMiss.kutty`](#historyCacheMiss.kutty) +### <a name="historyCacheMiss.htmx"></a> Event - [`historyCacheMiss.htmx`](#historyCacheMiss.htmx) This event is triggered when a cache miss occurs when restoring history @@ -69,7 +69,7 @@ This event is triggered when a cache miss occurs when restoring history * `detail.xhr` - the `XMLHttpRequest` that will retrieve the remote content for restoration * `detail.path` - the path and query of the page being restored -### <a name="historyCacheMissLoad.kutty"></a> Event - [`historyCacheMissLoad.kutty`](#historyCacheMissLoad.kutty) +### <a name="historyCacheMissLoad.htmx"></a> Event - [`historyCacheMissLoad.htmx`](#historyCacheMissLoad.htmx) This event is triggered when a cache miss occurs and a response has been retrieved succesfully from the server for the content to restore @@ -79,7 +79,7 @@ for the content to restore * `detail.xhr` - the `XMLHttpRequest` * `detail.path` - the path and query of the page being restored -### <a name="historyCacheMissError.kutty"></a> Event - [`historyCacheMissError.kutty`](#historyCacheMissError.kutty) +### <a name="historyCacheMissError.htmx"></a> Event - [`historyCacheMissError.htmx`](#historyCacheMissError.htmx) This event is triggered when a cache miss occurs and a response has been retrieved from the server for the content to restore, but the response is an error (e.g. `404`) @@ -89,26 +89,26 @@ for the content to restore, but the response is an error (e.g. `404`) * `detail.xhr` - the `XMLHttpRequest` * `detail.path` - the path and query of the page being restored -### <a name="historyRestore.kutty"></a> Event - [`historyRestore.kutty`](#historyRestore.kutty) +### <a name="historyRestore.htmx"></a> Event - [`historyRestore.htmx`](#historyRestore.htmx) -This event is triggered when kutty handles a history restoration action +This event is triggered when htmx handles a history restoration action ##### Details * `detail.path` - the path and query of the page being restored -### <a name="beforeHistorySave.kutty"></a> Event - [`beforeHistorySave.kutty`](#beforeHistorySave.kutty) +### <a name="beforeHistorySave.htmx"></a> Event - [`beforeHistorySave.htmx`](#beforeHistorySave.htmx) -This event is triggered when kutty handles a history restoration action +This event is triggered when htmx handles a history restoration action ##### Details * `detail.path` - the path and query of the page being restored * `detail.historyElt` - the history element being restored into -### <a name="initSSE.kutty"></a> Event - [`initSSE.kutty`](#initSSE.kutty) +### <a name="initSSE.htmx"></a> Event - [`initSSE.htmx`](#initSSE.htmx) -This event is triggered when kutty initializes a new SSE source. It can be used +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. @@ -117,15 +117,15 @@ Note that by default `withCredentials` will be set to `true` in the configuratio * `detail.config` - the config that will be passed to the `EventSource` contstructor -### <a name="load.kutty"></a> Event - [`load.kutty`](#load.kutty) +### <a name="load.htmx"></a> Event - [`load.htmx`](#load.htmx) -This event is triggered when a new node is loaded into the DOM by kutty. +This event is triggered when a new node is loaded into the DOM by htmx. ##### Details * `detail.elt` - the newly added element -### <a name="noSSESourceError.kutty"></a> Event - [`noSSESourceError.kutty`](#noSSESourceError.kutty) +### <a name="noSSESourceError.htmx"></a> Event - [`noSSESourceError.htmx`](#noSSESourceError.htmx) This event is triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined @@ -133,7 +133,7 @@ This event is triggered when an element refers to a SSE event in its trigger, bu * `detail.elt` - the element with the bad SSE trigger -### <a name="onLoadError.kutty"></a> Event - [`onLoadError.kutty`](#onLoadError.kutty) +### <a name="onLoadError.htmx"></a> Event - [`onLoadError.htmx`](#onLoadError.htmx) This event is triggered when an error occurs during the `load` handling of an AJAX call @@ -144,7 +144,7 @@ This event is triggered when an error occurs during the `load` handling of an AJ * `detail.target` - the target of the request * `detail.exception` - the exception that occurred -### <a name="oobErrorNoTarget.kutty"></a> Event - [`oobErrorNoTarget.kutty`](#oobErrorNoTarget.kutty) +### <a name="oobErrorNoTarget.htmx"></a> Event - [`oobErrorNoTarget.htmx`](#oobErrorNoTarget.htmx) This event is triggered when an [out of band swap](/docs##oob_swaps) does not have a corresponding element in the DOM to switch with. @@ -153,9 +153,9 @@ in the DOM to switch with. * `detail.content` - the element with the bad oob `id` -### <a name="prompt.kutty"></a> Event - [`prompt.kutty`](#prompt.kutty) +### <a name="prompt.htmx"></a> Event - [`prompt.htmx`](#prompt.htmx) -This event is triggered after a prompt has been shown to the user with the [`kt-prompt`](/attributes/kt-prompt) +This event is triggered after a prompt has been shown to the user with the [`hx-prompt`](/attributes/hx-prompt) attribute. If this event is cancelled, the AJAX request will not occur. ##### Details @@ -164,7 +164,7 @@ attribute. If this event is cancelled, the AJAX request will not occur. * `detail.target` - the target of the request * `detail.prompt` - the user response to the prompt -### <a name="responseError.kutty"></a> Event - [`responseError.kutty`](#responseError.kutty) +### <a name="responseError.htmx"></a> Event - [`responseError.htmx`](#responseError.htmx) This event is triggered when an HTTP error response occurs @@ -174,7 +174,7 @@ This event is triggered when an HTTP error response occurs * `detail.elt` - the element that triggered the request * `detail.target` - the target of the request -### <a name="sendError.kutty"></a> Event - [`sendError.kutty`](#sendError.kutty) +### <a name="sendError.htmx"></a> Event - [`sendError.htmx`](#sendError.htmx) This event is triggered when a network error prevents an HTTP request from occurring @@ -184,7 +184,7 @@ This event is triggered when a network error prevents an HTTP request from occur * `detail.elt` - the element that triggered the request * `detail.target` - the target of the request -### <a name="sseError.kutty"></a> Event - [`sseError.kutty`](#sseError.kutty) +### <a name="sseError.htmx"></a> Event - [`sseError.htmx`](#sseError.htmx) This event is triggered when an error occurs with a SSE source @@ -194,7 +194,7 @@ This event is triggered when an error occurs with a SSE source * `detail.error` - the error * `detail.source` - the SSE source -### <a name="swapError.kutty"></a> Event - [`swapError.kutty`](#swapError.kutty) +### <a name="swapError.htmx"></a> Event - [`swapError.htmx`](#swapError.htmx) This event is triggered when an error occurs during the swap phase @@ -204,13 +204,13 @@ This event is triggered when an error occurs during the swap phase * `detail.elt` - the element that triggered the request * `detail.target` - the target of the request -### <a name="configRequest.kutty"></a> Event - [`configRequest.kutty`](#configRequest.kutty) +### <a name="configRequest.htmx"></a> Event - [`configRequest.htmx`](#configRequest.htmx) -This event is triggered after kutty has collected parameters for inclusion in the request. It can be -used to include or update the parameters that kutty will send: +This event is triggered after htmx has collected parameters for inclusion in the request. It can be +used to include or update the parameters that htmx will send: ```javascript -document.body.addEventListener('configRequest.kutty', function(evt) { +document.body.addEventListener('configRequest.htmx', function(evt) { evt.detail.parameters['auth_token'] = getAuthToken(); // add a new parameter into the mix }); ``` @@ -227,9 +227,9 @@ than a single value. * `detail.target` - the target of the request * `detail.verb` - the HTTP verb in use -### <a name="targetError.kutty"></a> Event - [`targetError.kutty`](#targetError.kutty) +### <a name="targetError.htmx"></a> Event - [`targetError.htmx`](#targetError.htmx) -This event is triggered when a bad selector is used for a [`kt-target`](/attributes/kt-target) attribute (e.g. an +This event is triggered when a bad selector is used for a [`hx-target`](/attributes/hx-target) attribute (e.g. an element id without a preceding `#`) ##### Details diff --git a/www/examples.md b/www/examples.md index 580b1812..0e48a897 100644 --- a/www/examples.md +++ b/www/examples.md @@ -1,11 +1,11 @@ --- layout: layout.njk -title: </> kutty - UX Patterns +title: </> htmx - UX Patterns --- ## UI Examples -Below are a set of UX patterns implemented in kutty with minimal HTML and styling. +Below are a set of UX patterns implemented in htmx with minimal HTML and styling. You can copy and paste them and then adjust them for your needs. diff --git a/www/examples/active-search.md b/www/examples/active-search.md index fa39e541..7f2b7cbd 100644 --- a/www/examples/active-search.md +++ b/www/examples/active-search.md @@ -11,16 +11,16 @@ We start with a search input and an empty table: ```html <h3> Search Contacts - <span class="kutty-indicator"> + <span class="htmx-indicator"> <img src="/img/bars.svg"/> Searching... </span> </h3> <input class="form-control" type="text" name="search" placeholder="Begin Typing To Search Users..." - kt-post="/search" - kt-trigger="keyup changed delay:500ms" - kt-target="#search-results" - kt-indicator=".kutty-indicator"> + hx-post="/search" + hx-trigger="keyup changed delay:500ms" + hx-target="#search-results" + hx-indicator=".htmx-indicator"> <table class="table"> <thead> @@ -41,7 +41,7 @@ We add the `delay:500ms` modifier to the trigger to delay sending the query unti we add the `changed` modifier to the trigger to ensure we don't send new queries when the user doesn't change the value of the input (e.g. they hit an arrow key). -Finally, we show an indicator when the search is in flight with the `kt-indicator` attribute. +Finally, we show an indicator when the search is in flight with the `hx-indicator` attribute. {% include demo_ui.html.liquid %} @@ -67,17 +67,17 @@ Finally, we show an indicator when the search is in flight with the `kt-indicato function searchUI() { return ` <h3> Search Contacts -<span class="kutty-indicator"> +<span class="htmx-indicator"> <img src="/img/bars.svg"/> Searching... </span> </h3> <input class="form-control" type="text" name="search" placeholder="Begin Typing To Search Users..." - kt-post="/search" - kt-trigger="keyup changed delay:500ms" - kt-target="#search-results" - kt-indicator=".kutty-indicator"> + hx-post="/search" + hx-trigger="keyup changed delay:500ms" + hx-target="#search-results" + hx-indicator=".htmx-indicator"> <table class="table"> <thead> diff --git a/www/examples/bulk-update.md b/www/examples/bulk-update.md index fb12fe09..072d157f 100644 --- a/www/examples/bulk-update.md +++ b/www/examples/bulk-update.md @@ -9,9 +9,9 @@ accomplished by putting a form around a table, with checkboxes in the table, and values in `POST`'s to two different endpoints: `activate` and `deactivate`: ```html -<div kt-include="#checked-contacts" kt-target="#tbody"> - <a class="btn" kt-put="/activate">Activate</a> - <a class="btn" kt-put="/deactivate">Deactivate</a> +<div hx-include="#checked-contacts" hx-target="#tbody"> + <a class="btn" hx-put="/activate">Activate</a> + <a class="btn" hx-put="/deactivate">Deactivate</a> </div> <form id="checked-contacts"> @@ -42,10 +42,10 @@ updated rows. It will apply the class `activate` or `deactivate` to rows that h us to use a bit of CSS to flash a color helping the user see what happened: ```css - .kutty-settling tr.deactivate td { + .htmx-settling tr.deactivate td { background: lightcoral; } - .kutty-settling tr.activate td { + .htmx-settling tr.activate td { background: darkseagreen; } tr td { @@ -56,10 +56,10 @@ us to use a bit of CSS to flash a color helping the user see what happened: You can see a working examle of this code below. <style scoped=""> - .kutty-settling tr.deactivate td { + .htmx-settling tr.deactivate td { background: lightcoral; } - .kutty-settling tr.activate td { + .htmx-settling tr.activate td { background: darkseagreen; } tr td { @@ -127,9 +127,9 @@ You can see a working examle of this code below. // templates function displayUI(contacts) { - return `<div kt-include="#checked-contacts" kt-target="#tbody"> - <a class="btn" kt-put="/activate">Activate</a> - <a class="btn" kt-put="/deactivate">Deactivate</a> + return `<div hx-include="#checked-contacts" hx-target="#tbody"> + <a class="btn" hx-put="/activate">Activate</a> + <a class="btn" hx-put="/deactivate">Deactivate</a> </div> <form id="checked-contacts"> diff --git a/www/examples/click-to-edit.md b/www/examples/click-to-edit.md index 189a18b3..e61946c6 100644 --- a/www/examples/click-to-edit.md +++ b/www/examples/click-to-edit.md @@ -9,11 +9,11 @@ The click to edit pattern provides a way to offer inline editing of all or part * This pattern starts with a UI that shows the details of a contact. The div has a button that will get the editing UI for the contact from `/contacts/1/edit` ```html -<div kt-target="this" kt-swap="outerHTML"> +<div hx-target="this" hx-swap="outerHTML"> <div><label>First Name</label>: Joe</div> <div><label>Last Name</label>: Blow</div> <div><label>Email</label>: joe@blow.com</div> - <button kt-get="/contact/1/edit" class="btn btn-primary"> + <button hx-get="/contact/1/edit" class="btn btn-primary"> Click To Edit </button> </div> @@ -22,7 +22,7 @@ The click to edit pattern provides a way to offer inline editing of all or part * This returns a form that can be used to edit the contact ```html -<form kt-put="/contact/1" kt-target="this" kt-swap="outerHTML"> +<form hx-put="/contact/1" hx-target="this" hx-swap="outerHTML"> <div> <label>First Name</label> <input type="text" name="firstName" value="Joe"> @@ -36,7 +36,7 @@ The click to edit pattern provides a way to offer inline editing of all or part <input type="email" name="email" value="joe@blow.com"> </div> <button class="btn">Submit</button> - <button class="btn" kt-get="/contact/1">Cancel</button> + <button class="btn" hx-get="/contact/1">Cancel</button> </form> ``` @@ -74,7 +74,7 @@ The click to edit pattern provides a way to offer inline editing of all or part // templates function formTemplate(contact) { -return `<form kt-put="/contact/1" kt-target="this" kt-swap="outerHTML"> +return `<form hx-put="/contact/1" hx-target="this" hx-swap="outerHTML"> <div> <label>First Name</label> <input type="text" name="firstName" value="${contact.firstName}"> @@ -88,16 +88,16 @@ return `<form kt-put="/contact/1" kt-target="this" kt-swap="outerHTML"> <input type="email" name="email" value="${contact.email}"> </div> <button class="btn">Submit</button> - <button class="btn" kt-get="/contact/1">Cancel</button> + <button class="btn" hx-get="/contact/1">Cancel</button> </form>` } function displayTemplate(contact) { - return `<div kt-target="this" kt-swap="outerHTML"> + return `<div hx-target="this" hx-swap="outerHTML"> <div><label>First Name</label>: ${contact.firstName}</div> <div><label>Last Name</label>: ${contact.lastName}</div> <div><label>Email</label>: ${contact.email}</div> - <button kt-get="/contact/1/edit" class="btn btn-primary"> + <button hx-get="/contact/1/edit" class="btn btn-primary"> Click To Edit </button> </div>`; diff --git a/www/examples/click-to-load.md b/www/examples/click-to-load.md index 19190fdf..72ff0d38 100644 --- a/www/examples/click-to-load.md +++ b/www/examples/click-to-load.md @@ -10,10 +10,10 @@ the final row: ```html <tr id="replaceMe"> <td colspan="3"> - <button class='btn' kt-get="/contacts/?page=2" - kt-target="#replaceMe" - kt-swap="outerHTML"> - Load More Agents... <img class="kutty-indicator" src="/img/bars.svg"> + <button class='btn' hx-get="/contacts/?page=2" + hx-target="#replaceMe" + hx-swap="outerHTML"> + Load More Agents... <img class="htmx-indicator" src="/img/bars.svg"> </button> </td> </tr> @@ -83,10 +83,10 @@ results (which will contain a button to load the *next* page of results). And s return `<tr id="replaceMe"> <td colspan="3"> <center> - <button class='btn' kt-get="/contacts/?page=${page + 1}" - kt-target="#replaceMe" - kt-swap="outerHTML"> - Load More Agents... <img class="kutty-indicator" src="/img/bars.svg"> + <button class='btn' hx-get="/contacts/?page=${page + 1}" + hx-target="#replaceMe" + hx-swap="outerHTML"> + Load More Agents... <img class="htmx-indicator" src="/img/bars.svg"> </button> </center> </td> diff --git a/www/examples/infinite-scroll.md b/www/examples/infinite-scroll.md index 2cdc0fb8..2b71e080 100644 --- a/www/examples/infinite-scroll.md +++ b/www/examples/infinite-scroll.md @@ -2,16 +2,16 @@ layout: demo_layout.njk --- -## Kutty Pattern: Infinite scroll +## Htmx Pattern: Infinite scroll The infinite scroll pattern provides a way to load content dynamically on user scrolling action. Let's focus on the final row: ```html -<tr kt-get="/contacts/?page=2" - kt-trigger="revealed" - kt-swap="afterend"> +<tr hx-get="/contacts/?page=2" + hx-trigger="revealed" + hx-swap="afterend"> <td>Agent Smith</td> <td>void29@null.org</td> <td>55F49448C0</td> @@ -65,9 +65,9 @@ The last element of the results will itself contain the listener to load the *ne // templates function tableTemplate(contacts) { - return `<table kt-indicator=".kutty-indicator"><thead><tr><th>Name</th><th>Email</th><th>ID</th></tr></thead><tbody> + return `<table hx-indicator=".htmx-indicator"><thead><tr><th>Name</th><th>Email</th><th>ID</th></tr></thead><tbody> ${rowsTemplate(1, contacts)} - </tbody></table><center><img class="kutty-indicator" width="60" src="/img/bars.svg"></center>` + </tbody></table><center><img class="htmx-indicator" width="60" src="/img/bars.svg"></center>` } function rowsTemplate(page, contacts) { @@ -78,7 +78,7 @@ The last element of the results will itself contain the listener to load the *ne var c = contacts[i]; if (i == (contacts.length - 1)) { - trigger_attributes = ` kt-get="/contacts/?page=${page + 1}" kt-trigger="revealed" kt-swap="afterend"` + trigger_attributes = ` hx-get="/contacts/?page=${page + 1}" hx-trigger="revealed" hx-swap="afterend"` } txt += "<tr" + trigger_attributes +"><td>" + c.name + "</td><td>" + c.email + "</td><td>" + c.id + "</td></tr>\n"; diff --git a/www/examples/inline-validation.md b/www/examples/inline-validation.md index 492edfa6..c303ebdd 100644 --- a/www/examples/inline-validation.md +++ b/www/examples/inline-validation.md @@ -12,11 +12,11 @@ We start with this form: ```html <h3>Signup Form</h3> -<form kt-post="/contact"> - <div kt-target="this" kt-swap="outerHTML"> +<form hx-post="/contact"> + <div hx-target="this" hx-swap="outerHTML"> <label>Email Address</label> - <input name="email" kt-post="/contact/email" kt-indicator="#ind"> - <img id="ind" src="/img/bars.svg" class="kutty-indicator"/> + <input name="email" hx-post="/contact/email" hx-indicator="#ind"> + <img id="ind" src="/img/bars.svg" class="htmx-indicator"/> </div> <div class="form-group"> <label>First Name</label> @@ -37,10 +37,10 @@ It also specifies an indicator for the request. When a request occurs, it will return a partial to replace the outer div. It might look like this: ```html -<div kt-target="this" kt-swap="outerHTML" class="error"> +<div hx-target="this" hx-swap="outerHTML" class="error"> <label>Email Address</label> - <input name="email" kt-post="/contact/email" kt-indicator="#ind" value="test@foo.com"> - <img id="ind" src="/img/bars.svg" class="kutty-indicator"/> + <input name="email" hx-post="/contact/email" hx-indicator="#ind" value="test@foo.com"> + <img id="ind" src="/img/bars.svg" class="htmx-indicator"/> <div class='error-message'>That email is already taken. Please enter another email.</div> </div> ``` @@ -108,10 +108,10 @@ Below is a working demo of this example. The only email that will be accepted i // templates function formTemplate(page) { return `<h3>Signup Form</h3><form ic-post-to="/contact"> - <div kt-target="this" kt-swap="outerHTML"> + <div hx-target="this" hx-swap="outerHTML"> <label>Email Address</label> - <input name="email" kt-get="/contact/email" kt-indicator="#ind"> - <img id="ind" src="/img/bars.svg" class="kutty-indicator"/> + <input name="email" hx-get="/contact/email" hx-indicator="#ind"> + <img id="ind" src="/img/bars.svg" class="htmx-indicator"/> </div> <div class="form-group"> <label>First Name</label> @@ -126,10 +126,10 @@ Below is a working demo of this example. The only email that will be accepted i } function emailInputTemplate(val, errorMsg) { - return `<div kt-target="this" kt-swap="outerHTML" class="${errorMsg ? "error" : "valid"}"> + return `<div hx-target="this" hx-swap="outerHTML" class="${errorMsg ? "error" : "valid"}"> <label>Email Address</label> - <input name="email" kt-get="/contact/email" kt-indicator="#ind" value="${val}"> - <img id="ind" src="/img/bars.svg" class="kutty-indicator"/> + <input name="email" hx-get="/contact/email" hx-indicator="#ind" value="${val}"> + <img id="ind" src="/img/bars.svg" class="htmx-indicator"/> ${errorMsg ? ("<div class='error-message'>" + errorMsg + "</div>") : ""} </div>`; } diff --git a/www/examples/lazy-load.md b/www/examples/lazy-load.md index 0fe87202..806e414c 100644 --- a/www/examples/lazy-load.md +++ b/www/examples/lazy-load.md @@ -8,8 +8,8 @@ This example shows how to lazily load an element on a page. We start with an in state that looks like this: ```html -<div kt-get="/graph" kt-trigger="load"> - <img class="kutty-indicator" width="150" src="/img/bars.svg"/> +<div hx-get="/graph" hx-trigger="load"> + <img class="htmx-indicator" width="150" src="/img/bars.svg"/> </div> ``` @@ -17,7 +17,7 @@ Which shows a progress indicator as we are loading the graph. The graph is then loaded and faded gently into view via a settling CSS transition: ```css -.kutty-settling img { +.htmx-settling img { opacity: 0; } img { @@ -26,7 +26,7 @@ img { ``` <style> -.kutty-settling img { +.htmx-settling img { opacity: 0; } img { @@ -54,8 +54,8 @@ img { // templates function lazyTemplate(page) { - return `<div kt-get="/graph" kt-trigger="load"> - <img class="kutty-indicator" width="120" src="/img/bars.svg"/> + return `<div hx-get="/graph" hx-trigger="load"> + <img class="htmx-indicator" width="120" src="/img/bars.svg"/> </div>`; } </script> diff --git a/www/examples/progress-bar.md b/www/examples/progress-bar.md index 1c195a8b..de56e84d 100644 --- a/www/examples/progress-bar.md +++ b/www/examples/progress-bar.md @@ -9,9 +9,9 @@ This example shows how to implement a smoothly scrolling progress bar. We start with an intial state with a button that issues a `POST` to `/start` to begin the job: ```html -<div kt-target="this" kt-swap="outerHTML"> +<div hx-target="this" hx-swap="outerHTML"> <h3>Start Progress</h3> - <button class="btn" kt-post="/start"> + <button class="btn" hx-post="/start"> Start Job </button> </div> @@ -20,10 +20,10 @@ We start with an intial state with a button that issues a `POST` to `/start` to This div is then replaced with a new div that reloads itself every 600ms: ```html -<div kt-target="this" - kt-get="/job" - kt-trigger="load delay:600ms" - kt-swap="outerHTML"> +<div hx-target="this" + hx-get="/job" + hx-trigger="load delay:600ms" + hx-swap="outerHTML"> <h3>Running</h3> <div class="progress"> <div id="pb" class="progress-bar" style="width:0%"> @@ -31,23 +31,23 @@ This div is then replaced with a new div that reloads itself every 600ms: </div> ``` This HTML is rerendered every 600 milliseconds, with the "width" style attribute on the progress bar being updated. -Because there is an id on the progress bar div, kutty will smoothly transition between requests by settling the +Because there is an id on the progress bar div, htmx will smoothly transition between requests by settling the style attribute into its new value. This, when coupled with CSS transitions, make the visual transition continuous rather than jumpy. Finally, when the process is complete, a restart button is added to the UI: ```html -<div kt-target="this" - kt-get="/job" - kt-trigger="none" - kt-swap="outerHTML"> +<div hx-target="this" + hx-get="/job" + hx-trigger="none" + hx-swap="outerHTML"> <h3>Complete</h3> <div class="progress"> <div id="pb" class="progress-bar" style="width:100%"> </div> </div> -<button id="restart-btn" class="btn" kt-post="/start" kt-classes="add show:600ms"> +<button id="restart-btn" class="btn" hx-post="/start" hx-classes="add show:600ms"> Restart Job </button> ``` @@ -109,19 +109,19 @@ Finally, when the process is complete, a restart button is added to the UI: // templates function startButton(message) { - return `<div kt-target="this" kt-swap="outerHTML"> + return `<div hx-target="this" hx-swap="outerHTML"> <h3>${message}</h3> - <button class="btn" kt-post="/start"> + <button class="btn" hx-post="/start"> Start Job </button> </div>`; } function jobStatusTemplate(job) { - return `<div kt-target="this" - kt-get="/job" - kt-trigger="${job.complete ? 'none' : 'load delay:600ms'}" - kt-swap="outerHTML"> + return `<div hx-target="this" + hx-get="/job" + hx-trigger="${job.complete ? 'none' : 'load delay:600ms'}" + hx-swap="outerHTML"> <h3>${job.complete ? "Complete" : "Running"}</h3> <div class="progress"> <div id="pb" class="progress-bar" style="width:${job.percentComplete}%"> @@ -132,7 +132,7 @@ ${restartButton(job)}`; function restartButton(job) { if(job.complete){ - return `<button id="restart-btn" class="btn" kt-post="/start" kt-classes="add show:600ms"> + return `<button id="restart-btn" class="btn" hx-post="/start" hx-classes="add show:600ms"> Restart Job </button>` } else { diff --git a/www/examples/value-select.md b/www/examples/value-select.md index 07e4205a..06a4e192 100644 --- a/www/examples/value-select.md +++ b/www/examples/value-select.md @@ -14,7 +14,7 @@ Here is the code: ```html <div> <label >Make</label> - <select name="make" kt-get="/models" kt-target="#models" kt-indicator=".kutty-indicator"> + <select name="make" hx-get="/models" hx-target="#models" hx-indicator=".htmx-indicator"> <option value="audi">Audi</option> <option value="toyota">Toyota</option> <option value="bmw">BMW</option> @@ -63,7 +63,7 @@ And they become available in the `model` select. <form> <div> <label >Make</label> - <select name="make" kt-get="/models" kt-target="#models" kt-indicator=".kutty-indicator"> + <select name="make" hx-get="/models" hx-target="#models" hx-indicator=".htmx-indicator"> <option value="audi">Audi</option> <option value="toyota">Toyota</option> <option value="bmw">BMW</option> @@ -76,7 +76,7 @@ And they become available in the `model` select. <option value="a3">A3</option> <option value="a6">A6</option> </select> - <img class="kutty-indicator" width="20" src="/img/bars.svg"> + <img class="htmx-indicator" width="20" src="/img/bars.svg"> </div> </form>`; } diff --git a/www/headers/x-kt-trigger.md b/www/headers/x-ht-trigger.md index 65ad2ed6..55f8b7e8 100644 --- a/www/headers/x-kt-trigger.md +++ b/www/headers/x-ht-trigger.md @@ -1,16 +1,16 @@ --- layout: layout.njk -title: </> kutty - X-KT-Trigger +title: </> htmx - X-HX-Trigger --- -## `X-KT-Trigger` Response Header +## `X-HX-Trigger` Response Header -The `X-KT-Trigger` response header can be used to trigger client side actions from a response to kutty. You can +The `X-HX-Trigger` response header can be used to trigger client side actions from a response to htmx. You can trigger a single event or as many uniquely named events as you would like. To trigger a single event with no additional details you can simply send the header like so: -`X-KT-Trigger: myEvent` +`X-HX-Trigger: myEvent` This will trigger `myEvent` on the triggering element and will bubble up to the body. As an example you could listen for this event like this: @@ -23,7 +23,7 @@ document.body.addEventListener("myEvent", function(evt){ If you want to pass details along with the event, you can move to JSON for the value of the trigger: -`X-KT-Trigger: {"showMessage":"Here Is A Message"}` +`X-HX-Trigger: {"showMessage":"Here Is A Message"}` To handle this event you would write the following code: @@ -36,7 +36,7 @@ document.body.addEventListener("showMessage", function(evt){ Note that the value of the message was put into the `detail.value` slot. If you wish to pass multiple pieces of data you can use a nested JSON object on the right hand side of the JSON object: -`X-KT-Trigger: {"showMessage":{"level" : "info", "message" : "Here Is A Message"}}` +`X-HX-Trigger: {"showMessage":{"level" : "info", "message" : "Here Is A Message"}}` And handle this event like so: @@ -53,6 +53,6 @@ Each property of the JSON object on the right hand side will be copied onto the Finally, if you wish to invoke multiple events, you can simply add additional properties to the top level JSON object: -`X-KT-Trigger: {"event1":"A message", "event2":"Another message"}` +`X-HX-Trigger: {"event1":"A message", "event2":"Another message"}` -Using events gives you a lot of flexibility to add functionality to normal kutty responses.
\ No newline at end of file +Using events gives you a lot of flexibility to add functionality to normal htmx responses.
\ No newline at end of file diff --git a/www/img/kutty_logo.2.png b/www/img/htmx_logo.2.png Binary files differindex 533a968a..533a968a 100644 --- a/www/img/kutty_logo.2.png +++ b/www/img/htmx_logo.2.png diff --git a/www/img/kutty_placeholder.png b/www/img/kutty_placeholder.png Binary files differdeleted file mode 100644 index d8d7fc5a..00000000 --- a/www/img/kutty_placeholder.png +++ /dev/null diff --git a/www/index.md b/www/index.md index f4cd1bd4..8552f3b2 100644 --- a/www/index.md +++ b/www/index.md @@ -1,37 +1,37 @@ --- layout: layout.njk -title: </> kutty - high power tools for html +title: </> htmx - high power tools for html --- -<div class="dark-hero full-width" kt-classes="add appear"> - <span class="logo dark"><<a>/</a>> <span class="no-mobile">k<a>u</a>tty</span></span> +<div class="dark-hero full-width" hx-classes="add appear"> + <span class="logo dark"><<a>/</a>> <span class="no-mobile">htm<a>x</a></span></span> <sub class="no-mobile"><i>high power tools for HTML</i></sub> </div> ## Introduction -Kutty is a set of extensions (attributes, request headers, etc.) that help you build +Htmx is a set of extensions (attributes, request headers, etc.) that help you build [modern UI](/examples) with the [simplicity](https://en.wikipedia.org/wiki/HATEOAS) and [power](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) of HTML. -Kutty is small ([~6k min.gz'd](https://unpkg.com/kutty.org/dist/)), IE11 compatible, [dependency-free](https://github.com/bigskysoftware/kutty/blob/master/package.json) +Htmx is small ([~6k min.gz'd](https://unpkg.com/htmx.org/dist/)), IE11 compatible, [dependency-free](https://github.com/bigskysoftware/htmx/blob/master/package.json) & you can try it out quickly, without a huge rewrite. ## Quick Start ```html <!-- Load from unpkg --> - <script src="https://unpkg.com/kutty.org@0.0.2"></script> + <script src="https://unpkg.com/htmx.org@0.0.2"></script> <!-- have a button POST a click via AJAX --> - <button kt-post="/clicked" kt-swap="outerHTML"> + <button hx-post="/clicked" hx-swap="outerHTML"> Click Me </button> ``` -The `kt-post` and `kt-swap` attributes tell kutty: +The `hx-post` and `hx-swap` attributes tell htmx: > "When a user clicks on this button, issue an AJAX request to /clicked, and replace the entire button with the response" -Kutty is based on [intercooler.js](http://intercoolerjs.org) and is the successor to that project. +Htmx is based on [intercooler.js](http://intercoolerjs.org) and is the successor to that project. diff --git a/www/js/kutty.js b/www/js/kutty.js deleted file mode 100644 index 35ce3150..00000000 --- a/www/js/kutty.js +++ /dev/null @@ -1,1306 +0,0 @@ -// noinspection JSUnusedAssignment -var kutty = kutty || (function () { - 'use strict'; - - var VERBS = ['get', 'post', 'put', 'delete', 'patch'] - - //==================================================================== - // Utilities - //==================================================================== - - function parseInterval(str) { - if (str === "null" || str === "false" || str === "") { - return null; - } else if (str.lastIndexOf("ms") === str.length - 2) { - return parseFloat(str.substr(0, str.length - 2)); - } else if (str.lastIndexOf("s") === str.length - 1) { - return parseFloat(str.substr(0, str.length - 1)) * 1000; - } else { - return parseFloat(str); - } - } - - function getRawAttribute(elt, name) { - return elt.getAttribute && elt.getAttribute(name); - } - - // resolve with both kt and data-kt prefixes - function getAttributeValue(elt, qualifiedName) { - return getRawAttribute(elt, qualifiedName) || getRawAttribute(elt, "data-" + qualifiedName); - } - - function parentElt(elt) { - return elt.parentElement; - } - - function getDocument() { - return document; - } - - function getClosestMatch(elt, condition) { - if (condition(elt)) { - return elt; - } else if (parentElt(elt)) { - return getClosestMatch(parentElt(elt), condition); - } else { - return null; - } - } - - function getClosestAttributeValue(elt, attributeName) { - var closestAttr = null; - getClosestMatch(elt, function (e) { - return closestAttr = getRawAttribute(e, attributeName); - }); - return closestAttr; - } - - function matches(elt, selector) { - // noinspection JSUnresolvedVariable - var matchesFunction = elt.matches || - elt.matchesSelector || elt.msMatchesSelector || elt.mozMatchesSelector - || elt.webkitMatchesSelector || elt.oMatchesSelector; - return matchesFunction && matchesFunction.call(elt, selector); - } - - function getStartTag(str) { - var tagMatcher = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i - var match = tagMatcher.exec( str ); - if (match) { - return match[1].toLowerCase(); - } else { - return ""; - } - } - - function parseHTML(resp, depth) { - var parser = new DOMParser(); - var responseDoc = parser.parseFromString(resp, "text/html"); - var responseNode = responseDoc.body; - while (depth > 0) { - depth--; - responseNode = responseNode.firstChild; - } - return responseNode; - } - - function makeFragment(resp) { - var startTag = getStartTag(resp); - switch (startTag) { - case "thead": - case "tbody": - case "tfoot": - case "colgroup": - case "caption": - return parseHTML("<table>" + resp + "</table>", 1); - case "col": - return parseHTML("<table><colgroup>" + resp + "</colgroup></table>", 2); - case "tr": - return parseHTML("<table><tbody>" + resp + "</tbody></table>", 2); - case "td": - case "th": - return parseHTML("<table><tbody><tr>" + resp + "</tr></tbody></table>", 3); - default: - return parseHTML(resp, 0); - } - } - - function isType(o, type) { - return Object.prototype.toString.call(o) === "[object " + type + "]"; - } - - function isFunction(o) { - return isType(o, "Function"); - } - - function isRawObject(o) { - return isType(o, "Object"); - } - - function getInternalData(elt) { - var dataProp = 'kutty-internal-data'; - var data = elt[dataProp]; - if (!data) { - data = elt[dataProp] = {}; - } - return data; - } - - function forEach(arr, func) { - if (arr) { - for (var i = 0; i < arr.length; i++) { - func(arr[i]); - } - } - } - - function isScrolledIntoView(el) { - var rect = el.getBoundingClientRect(); - var elemTop = rect.top; - var elemBottom = rect.bottom; - return elemTop < window.innerHeight && elemBottom >= 0; - } - - function bodyContains(elt) { - return getDocument().body.contains(elt); - } - - function concat(arr1, arr2) { - return arr1.concat(arr2); - } - - function splitOnWhitespace(trigger) { - return trigger.split(/\s+/); - } - - function addRule(rule) { - var sheet = getDocument().styleSheets[0]; - sheet.insertRule(rule, sheet.cssRules.length); - } - - function mergeObjects(obj1, obj2) { - for (var key in obj2) { - if (obj2.hasOwnProperty(key)) { - obj1[key] = obj2[key]; - } - } - return obj1; - } - - //========================================================================================== - // public API - //========================================================================================== - - function internalEval(str){ - return eval(str); - } - - function onLoadHelper(callback) { - var value = kutty.on("load.kutty", function(evt) { - callback(evt.detail.elt); - }); - return value; - } - - function logAll(){ - kutty.logger = function(elt, event, data) { - if(console) { - console.log(event, elt, data); - } - } - } - - function find(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelector(selector); - } else { - return getDocument().body.querySelector(eltOrSelector); - } - } - - function findAll(eltOrSelector, selector) { - if (selector) { - return eltOrSelector.querySelectorAll(selector); - } else { - return getDocument().body.querySelectorAll(eltOrSelector); - } - } - - function removeElement(elt, delay) { - if (delay) { - setTimeout(function(){removeElement(elt);}, delay) - } else { - elt.parentElement.removeChild(elt); - } - } - - function addClassToElement(elt, clazz, delay) { - if (delay) { - setTimeout(function(){addClassToElement(elt, clazz);}, delay) - } else { - elt.classList.add(clazz); - } - } - - function removeClassFromElement(elt, clazz, delay) { - if (delay) { - setTimeout(function(){removeClassFromElement(elt, clazz);}, delay) - } else { - elt.classList.remove(clazz); - } - } - - function toggleClassOnElement(elt, clazz) { - elt.classList.toggle(clazz); - } - - function takeClassForElement(elt, clazz) { - forEach(elt.parentElement.children, function(child){ - removeClassFromElement(child, clazz); - }) - addClassToElement(elt, clazz); - } - - function closest(elt, selector) { - do if (elt == null || matches(elt, selector)) return elt; - while (elt = elt && parentElt(elt)); - } - - function processEventArgs(arg1, arg2, arg3) { - if (isFunction(arg2)) { - return { - target: getDocument().body, - event: arg1, - listener: arg2 - } - } else { - return { - target: arg1, - event: arg2, - listener: arg3 - } - } - - } - - function addKuttyEventListener(arg1, arg2, arg3) { - ready(function(){ - var eventArgs = processEventArgs(arg1, arg2, arg3); - eventArgs.target.addEventListener(eventArgs.event, eventArgs.listener); - }) - var b = isFunction(arg2); - return b ? arg2 : arg3; - } - - function removeKuttyEventListener(arg1, arg2, arg3) { - ready(function(){ - var eventArgs = processEventArgs(arg1, arg2, arg3); - eventArgs.target.removeEventListener(eventArgs.event, eventArgs.listener); - }) - return isFunction(arg2) ? arg2 : arg3; - } - - //==================================================================== - // Node processing - //==================================================================== - - function getTarget(elt) { - var explicitTarget = getClosestMatch(elt, function(e){return getRawAttribute(e,"kt-target") !== null}); - if (explicitTarget) { - var targetStr = getRawAttribute(explicitTarget, "kt-target"); - if (targetStr === "this") { - return explicitTarget; - } else if (targetStr.indexOf("closest ") === 0) { - return closest(elt, targetStr.substr(8)); - } else { - return getDocument().querySelector(targetStr); - } - } else { - var data = getInternalData(elt); - if (data.boosted) { - return getDocument().body; - } else { - return elt; - } - } - } - - function cloneAttributes(mergeTo, mergeFrom) { - forEach(mergeTo.attributes, function (attr) { - if (!mergeFrom.hasAttribute(attr.name)) { - mergeTo.removeAttribute(attr.name) - } - }); - forEach(mergeFrom.attributes, function (attr) { - mergeTo.setAttribute(attr.name, attr.value); - }); - } - - function handleOutOfBandSwaps(fragment) { - var settleTasks = []; - forEach(fragment.children, function (child) { - if (getAttributeValue(child, "kt-swap-oob") === "true") { - var target = getDocument().getElementById(child.id); - if (target) { - var fragment = getDocument().createDocumentFragment(); - fragment.appendChild(child); - settleTasks = settleTasks.concat(swapOuterHTML(target, fragment)); - } else { - child.parentNode.removeChild(child); - triggerErrorEvent(getDocument().body, "oobErrorNoTarget.kutty", {content: child}) - } - } - }); - return settleTasks; - } - - function handleAttributes(parentNode, fragment) { - var attributeSwaps = []; - forEach(fragment.querySelectorAll("[id]"), function (newNode) { - var oldNode = parentNode.querySelector(newNode.tagName + "[id=" + newNode.id + "]") - if (oldNode) { - var newAttributes = newNode.cloneNode(); - cloneAttributes(newNode, oldNode); - attributeSwaps.push(function () { - cloneAttributes(newNode, newAttributes); - }); - } - }); - return attributeSwaps; - } - - function insertNodesBefore(parentNode, insertBefore, fragment) { - var settleTasks = handleAttributes(parentNode, fragment); - while(fragment.childNodes.length > 0){ - var child = fragment.firstChild; - parentNode.insertBefore(child, insertBefore); - if (child.nodeType !== Node.TEXT_NODE) { - triggerEvent(child, 'load.kutty', {}); - processNode(child); - } - } - return settleTasks; - } - - function swapOuterHTML(target, fragment) { - if (target.tagName === "BODY") { - return swapInnerHTML(target, fragment); - } else { - var settleTasks = insertNodesBefore(parentElt(target), target, fragment); - parentElt(target).removeChild(target); - return settleTasks; - } - } - - function swapAfterBegin(target, fragment) { - return insertNodesBefore(target, target.firstChild, fragment); - } - - function swapBeforeBegin(target, fragment) { - return insertNodesBefore(parentElt(target), target, fragment); - } - - function swapBeforeEnd(target, fragment) { - return insertNodesBefore(target, null, fragment); - } - - function swapAfterEnd(target, fragment) { - return insertNodesBefore(parentElt(target), target.nextSibling, fragment); - } - - function swapInnerHTML(target, fragment) { - var firstChild = target.firstChild; - var settleTasks = insertNodesBefore(target, firstChild, fragment); - if (firstChild) { - while (firstChild.nextSibling) { - target.removeChild(firstChild.nextSibling); - } - target.removeChild(firstChild); - } - return settleTasks; - } - - function maybeSelectFromResponse(elt, fragment) { - var selector = getClosestAttributeValue(elt, "kt-select"); - if (selector) { - var newFragment = getDocument().createDocumentFragment(); - forEach(fragment.querySelectorAll(selector), function (node) { - newFragment.appendChild(node); - }); - fragment = newFragment; - } - return fragment; - } - - function swapResponse(swapStyle, target, elt, responseText) { - var fragment = makeFragment(responseText); - if (fragment) { - var settleTasks = handleOutOfBandSwaps(fragment); - - fragment = maybeSelectFromResponse(elt, fragment); - - switch(swapStyle) { - case "outerHTML": return concat(settleTasks, swapOuterHTML(target, fragment)); - case "afterbegin": return concat(settleTasks, swapAfterBegin(target, fragment)); - case "beforebegin": return concat(settleTasks, swapBeforeBegin(target, fragment)); - case "beforeend": return concat(settleTasks, swapBeforeEnd(target, fragment)); - case "afterend": return concat(settleTasks, swapAfterEnd(target, fragment)); - default: return concat(settleTasks, swapInnerHTML(target, fragment)); - } - } - } - - function handleTrigger(elt, trigger) { - if (trigger) { - if (trigger.indexOf("{") === 0) { - var triggers = JSON.parse(trigger); - for (var eventName in triggers) { - if (triggers.hasOwnProperty(eventName)) { - var detail = triggers[eventName]; - if (!isRawObject(detail)) { - detail = {"value": detail} - } - triggerEvent(elt, eventName, detail); - } - } - } else { - triggerEvent(elt, trigger, []); - } - } - } - - function getTriggerSpec(elt) { - - var triggerSpec = { - "trigger" : "click" - } - var explicitTrigger = getAttributeValue(elt, 'kt-trigger'); - if (explicitTrigger) { - var tokens = splitOnWhitespace(explicitTrigger); - if (tokens.length > 0) { - var trigger = tokens[0]; - if (trigger === "every") { - triggerSpec.pollInterval = parseInterval(tokens[1]); - } else if (trigger.indexOf("sse:") === 0) { - triggerSpec.sseEvent = trigger.substr(4); - } else { - triggerSpec['trigger'] = trigger; - for (var i = 1; i < tokens.length; i++) { - var token = tokens[i].trim(); - if (token === "changed") { - triggerSpec.changed = true; - } - if (token === "once") { - triggerSpec.once = true; - } - if (token.indexOf("delay:") === 0) { - triggerSpec.delay = parseInterval(token.substr(6)); - } - } - } - } - } else { - if (matches(elt, 'form')) { - triggerSpec['trigger'] = 'submit'; - } else if (matches(elt, 'input, textarea, select')) { - triggerSpec['trigger'] = 'change'; - } - } - return triggerSpec; - } - - function parseClassOperation(trimmedValue) { - var split = splitOnWhitespace(trimmedValue); - if (split.length > 1) { - var operation = split[0]; - var classDef = split[1].trim(); - var cssClass; - var delay; - if (classDef.indexOf(":") > 0) { - var splitCssClass = classDef.split(':'); - cssClass = splitCssClass[0]; - delay = parseInterval(splitCssClass[1]); - } else { - cssClass = classDef; - delay = 100; - } - return { - operation:operation, - cssClass:cssClass, - delay:delay - } - } else { - return null; - } - } - - function processClassList(elt, classList) { - forEach(classList.split("&"), function (run) { - var currentRunTime = 0; - forEach(run.split(","), function(value){ - var trimmedValue = value.trim(); - var classOperation = parseClassOperation(trimmedValue); - if (classOperation) { - if (classOperation.operation === "toggle") { - setTimeout(function () { - setInterval(function () { - elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass); - }, classOperation.delay); - }, currentRunTime); - currentRunTime = currentRunTime + classOperation.delay; - } else { - currentRunTime = currentRunTime + classOperation.delay; - setTimeout(function () { - elt.classList[classOperation.operation].call(elt.classList, classOperation.cssClass); - }, currentRunTime); - } - } - }); - }); - } - - function cancelPolling(elt) { - getInternalData(elt).cancelled = true; - } - - function processPolling(elt, verb, path, interval) { - var nodeData = getInternalData(elt); - nodeData.timeout = setTimeout(function () { - if (bodyContains(elt) && nodeData.cancelled !== true) { - issueAjaxRequest(elt, verb, path); - processPolling(elt, verb, getAttributeValue(elt, "kt-" + verb), interval); - } - }, interval); - } - - function isLocalLink(elt) { - return location.hostname === elt.hostname && - getRawAttribute(elt,'href') && - getRawAttribute(elt,'href').indexOf("#") !== 0; - } - - function boostElement(elt, nodeData, triggerSpec) { - if ((elt.tagName === "A" && isLocalLink(elt)) || elt.tagName === "FORM") { - nodeData.boosted = true; - var verb, path; - if (elt.tagName === "A") { - verb = "get"; - path = getRawAttribute(elt, 'href'); - } else { - var rawAttribute = getRawAttribute(elt, "method"); - verb = rawAttribute ? rawAttribute.toLowerCase() : "get"; - path = getRawAttribute(elt, 'action'); - } - addEventListener(elt, verb, path, nodeData, triggerSpec, true); - } - } - - function shouldCancel(elt) { - return elt.tagName === "FORM" || - (matches(elt, 'input[type="submit"], button') && closest(elt, 'form') !== null) || - (elt.tagName === "A" && elt.href && elt.href.indexOf('#') !== 0); - } - - function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { - var eventListener = function (evt) { - if(explicitCancel || shouldCancel(elt)) evt.preventDefault(); - var eventData = getInternalData(evt); - var elementData = getInternalData(elt); - if (!eventData.handled) { - eventData.handled = true; - if (triggerSpec.once) { - if (elementData.triggeredOnce) { - return; - } else { - elementData.triggeredOnce = true; - } - } - if (triggerSpec.changed) { - if (elementData.lastValue === elt.value) { - return; - } else { - elementData.lastValue = elt.value; - } - } - if (elementData.delayed) { - clearTimeout(elementData.delayed); - } - var issueRequest = function(){ - issueAjaxRequest(elt, verb, path, evt.target); - } - if (triggerSpec.delay) { - elementData.delayed = setTimeout(issueRequest, triggerSpec.delay); - } else { - issueRequest(); - } - } - }; - nodeData.trigger = triggerSpec.trigger; - nodeData.eventListener = eventListener; - elt.addEventListener(triggerSpec.trigger, eventListener); - } - - function initScrollHandler() { - if (!window['kuttyScrollHandler']) { - var scrollHandler = function() { - forEach(getDocument().querySelectorAll("[kt-trigger='revealed']"), function (elt) { - maybeReveal(elt); - }); - }; - window['kuttyScrollHandler'] = scrollHandler; - window.addEventListener("scroll", scrollHandler) - } - } - - function maybeReveal(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.revealed && isScrolledIntoView(elt)) { - nodeData.revealed = true; - issueAjaxRequest(elt, nodeData.verb, nodeData.path); - } - } - - function maybeCloseSSESource(elt) { - if (!bodyContains(elt)) { - elt.sseSource.close(); - return true; - } - } - - function initSSESource(elt, sseSrc) { - var detail = { - config:{withCredentials: true} - }; - triggerEvent(elt, "initSSE.kutty", detail); - var source = new EventSource(sseSrc, detail.config); - source.onerror = function (e) { - triggerErrorEvent(elt, "sseError.kutty", {error:e, source:source}); - maybeCloseSSESource(elt); - }; - getInternalData(elt).sseSource = source; - } - - function processSSETrigger(elt, verb, path, sseEventName) { - var sseSource = getClosestMatch(elt, function (parent) { - return parent.sseSource; - }); - if (sseSource) { - var sseListener = function () { - if (!maybeCloseSSESource(sseSource)) { - if (bodyContains(elt)) { - issueAjaxRequest(elt, verb, path); - } else { - sseSource.sseSource.removeEventListener(sseEventName, sseListener); - } - } - }; - sseSource.sseSource.addEventListener(sseEventName, sseListener); - } else { - triggerErrorEvent(elt, "noSSESourceError.kutty") - } - } - - function loadImmediately(elt, verb, path, nodeData, delay) { - var load = function(){ - if (!nodeData.loaded) { - nodeData.loaded = true; - issueAjaxRequest(elt, verb, path); - } - } - if (delay) { - setTimeout(load, delay); - } else { - load(); - } - } - - function processVerbs(elt, nodeData, triggerSpec) { - var explicitAction = false; - forEach(VERBS, function (verb) { - var path = getAttributeValue(elt, 'kt-' + verb); - if (path) { - explicitAction = true; - nodeData.path = path; - nodeData.verb = verb; - if (triggerSpec.sseEvent) { - processSSETrigger(elt, verb, path, triggerSpec.sseEvent); - } else if (triggerSpec.trigger === "revealed") { - initScrollHandler(); - maybeReveal(elt); - } else if (triggerSpec.trigger === "load") { - loadImmediately(elt, verb, path, nodeData, triggerSpec.delay); - } else if (triggerSpec.pollInterval) { - nodeData.polling = true; - processPolling(elt, verb, path, triggerSpec.pollInterval); - } else { - addEventListener(elt, verb, path, nodeData, triggerSpec); - } - } - }); - return explicitAction; - } - - function processNode(elt) { - var nodeData = getInternalData(elt); - if (!nodeData.processed) { - nodeData.processed = true; - - var triggerSpec = getTriggerSpec(elt); - var explicitAction = processVerbs(elt, nodeData, triggerSpec); - - if (!explicitAction && getClosestAttributeValue(elt, "kt-boost") === "true") { - boostElement(elt, nodeData, triggerSpec); - } - var sseSrc = getAttributeValue(elt, 'kt-sse-source'); - if (sseSrc) { - initSSESource(elt, sseSrc); - } - var addClass = getAttributeValue(elt, 'kt-classes'); - if (addClass) { - processClassList(elt, addClass); - } - } - if (elt.children) { // IE - forEach(elt.children, function(child) { processNode(child) }); - } - } - - //==================================================================== - // Event/Log Support - //==================================================================== - - function sendError(elt, eventName, detail) { - var errorURL = getClosestAttributeValue(elt, "kt-error-url"); - if (errorURL) { - var xhr = new XMLHttpRequest(); - xhr.open("POST", errorURL); - xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); - xhr.send(JSON.stringify({ "elt": elt.id, "event": eventName, "detail" : detail })); - } - } - - function makeEvent(eventName, detail) { - var evt; - if (window.CustomEvent && typeof window.CustomEvent === 'function') { - evt = new CustomEvent(eventName, {bubbles: true, cancelable: true, detail: detail}); - } else { - evt = getDocument().createEvent('CustomEvent'); - evt.initCustomEvent(eventName, true, true, detail); - } - return evt; - } - - function triggerErrorEvent(elt, eventName, detail) { - triggerEvent(elt, eventName, mergeObjects({isError:true}, detail)); - } - - function triggerEvent(elt, eventName, detail) { - detail["elt"] = elt; - var event = makeEvent(eventName, detail); - if (kutty.logger) { - kutty.logger(elt, eventName, detail); - if (detail.isError) { - sendError(elt, eventName, detail); - } - } - var eventResult = elt.dispatchEvent(event); - return eventResult; - } - - //==================================================================== - // History Support - //==================================================================== - var currentPathForHistory = null; - - function getHistoryElement() { - var historyElt = getDocument().querySelector('[kt-history-elt]'); - return historyElt || getDocument().body; - } - - function saveToHistoryCache(url, content, title, scroll) { - var historyCache = JSON.parse(localStorage.getItem("kutty-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - historyCache = historyCache.slice(i, 1); - break; - } - } - historyCache.push({url:url, content: content, title:title, scroll:scroll}) - while (historyCache.length > kutty.config.historyCacheSize) { - historyCache.shift(); - } - localStorage.setItem("kutty-history-cache", JSON.stringify(historyCache)); - } - - function getCachedHistory(url) { - var historyCache = JSON.parse(localStorage.getItem("kutty-history-cache")) || []; - for (var i = 0; i < historyCache.length; i++) { - if (historyCache[i].url === url) { - return historyCache[i]; - } - } - return null; - } - - function saveHistory() { - var elt = getHistoryElement(); - var path = currentPathForHistory || location.pathname+location.search; - triggerEvent(getDocument().body, "beforeHistorySave.kutty", {path:path, historyElt:elt}); - if(kutty.config.historyEnabled) history.replaceState({}, getDocument().title, window.location.href); - saveToHistoryCache(path, elt.innerHTML, getDocument().title, window.scrollY); - } - - function pushUrlIntoHistory(path) { - if(kutty.config.historyEnabled) history.pushState({}, "", path); - currentPathForHistory = path; - } - - function settleImmediately(settleTasks) { - forEach(settleTasks, function (task) { - task.call(); - }); - } - - function loadHistoryFromServer(path) { - var request = new XMLHttpRequest(); - var details = {path: path, xhr:request}; - triggerEvent(getDocument().body, "historyCacheMiss.kutty", details); - request.open('GET', path, true); - request.onload = function () { - if (this.status >= 200 && this.status < 400) { - triggerEvent(getDocument().body, "historyCacheMissLoad.kutty", details); - var fragment = makeFragment(this.response); - fragment = fragment.querySelector('[kt-history-elt]') || fragment; - settleImmediately(swapInnerHTML(getHistoryElement(), fragment)); - currentPathForHistory = path; - } else { - triggerErrorEvent(getDocument().body, "historyCacheMissLoadError.kutty", details); - } - }; - request.send(); - } - - function restoreHistory(path) { - saveHistory(currentPathForHistory); - path = path || location.pathname+location.search; - triggerEvent(getDocument().body, "historyRestore.kutty", {path:path}); - var cached = getCachedHistory(path); - if (cached) { - settleImmediately(swapInnerHTML(getHistoryElement(), makeFragment(cached.content))); - document.title = cached.title; - window.scrollTo(0, cached.scroll); - currentPathForHistory = path; - } else { - loadHistoryFromServer(path); - } - } - - function shouldPush(elt) { - return getClosestAttributeValue(elt, "kt-push-url") === "true" || - (elt.tagName === "A" && getInternalData(elt).boosted); - } - - function addRequestIndicatorClasses(elt) { - mutateRequestIndicatorClasses(elt, "add"); - } - - function removeRequestIndicatorClasses(elt) { - mutateRequestIndicatorClasses(elt, "remove"); - } - - function mutateRequestIndicatorClasses(elt, action) { - var indicator = getClosestAttributeValue(elt, 'kt-indicator'); - if (indicator) { - var indicators = getDocument().querySelectorAll(indicator); - } else { - indicators = [elt]; - } - forEach(indicators, function(ic) { - ic.classList[action].call(ic.classList, "kutty-request"); - }); - } - - //==================================================================== - // Input Value Processing - //==================================================================== - - function haveSeenNode(processed, elt) { - for (var i = 0; i < processed.length; i++) { - var node = processed[i]; - if (node.isSameNode(elt)) { - return true; - } - } - return false; - } - - function shouldInclude(elt) { - if(elt.name === "" || elt.name == null || elt.disabled) { - return false; - } - // ignore "submitter" types (see jQuery src/serialize.js) - if (elt.type === "button" || elt.type === "submit" || elt.tagName === "image" || elt.tagName === "reset" || elt.tagName === "file" ) { - return false; - } - if (elt.type === "checkbox" || elt.type === "radio" ) { - return elt.checked; - } - return true; - } - - function processInputValue(processed, values, elt) { - if (elt == null || haveSeenNode(processed, elt)) { - return; - } else { - processed.push(elt); - } - if (shouldInclude(elt)) { - var name = getRawAttribute(elt,"name"); - var value = elt.value; - if (name && value) { - var current = values[name]; - if(current) { - if (Array.isArray(current)) { - current.push(value); - } else { - values[name] = [current, value]; - } - } else { - values[name] = value; - } - } - } - if (matches(elt, 'form')) { - var inputs = elt.elements; - forEach(inputs, function(input) { - processInputValue(processed, values, input); - }); - } - } - - function getInputValues(elt, verb) { - var processed = []; - var values = {}; - // include the element itself - processInputValue(processed, values, elt); - - // include any explicit includes - var includes = getClosestAttributeValue(elt, "kt-include"); - if (includes) { - var nodes = getDocument().querySelectorAll(includes); - forEach(nodes, function(node) { - processInputValue(processed, values, node); - }); - } - - // for a non-GET include the closest form - if (verb !== 'get') { - processInputValue(processed, values, closest(elt, 'form')); - } - return values; - } - - function appendParam(returnStr, name, realValue) { - if (returnStr !== "") { - returnStr += "&"; - } - returnStr += encodeURIComponent(name) + "=" + encodeURIComponent(realValue); - return returnStr; - } - - function urlEncode(values) { - var returnStr = ""; - for (var name in values) { - if (values.hasOwnProperty(name)) { - var value = values[name]; - if (Array.isArray(value)) { - forEach(value, function(v) { - returnStr = appendParam(returnStr, name, v); - }); - } else { - returnStr = appendParam(returnStr, name, value); - } - } - } - return returnStr; - } - - //==================================================================== - // Ajax - //==================================================================== - - function getHeaders(elt, target, prompt, eventTarget) { - var headers = { - "X-KT-Request" : "true", - "X-KT-Trigger" : getRawAttribute(elt, "id"), - "X-KT-Trigger-Name" : getRawAttribute(elt, "name"), - "X-KT-Target" : getRawAttribute(target, "id"), - "Current-URL" : getDocument().location.href, - } - if (prompt) { - headers["X-KT-Prompt"] = prompt; - } - if (eventTarget) { - headers["X-KT-Event-Target"] = getRawAttribute(eventTarget, "id"); - } - if (getDocument().activeElement) { - headers["X-KT-Active-Element"] = getRawAttribute(getDocument().activeElement, "id"); - headers["X-KT-Active-Element-Name"] = getRawAttribute(getDocument().activeElement, "name"); - if (getDocument().activeElement.value) { - headers["X-KT-Active-Element-Value"] = getRawAttribute(getDocument().activeElement, "value"); - } - } - return headers; - } - - function filterValues(inputValues, elt, verb) { - var paramsValue = getClosestAttributeValue(elt, "kt-params"); - if (paramsValue) { - if (paramsValue === "none") { - return {}; - } else if (paramsValue === "*") { - return inputValues; - } else if(paramsValue.indexOf("not ") === 0) { - forEach(paramsValue.substr(4).split(","), function (name) { - name = name.trim(); - delete inputValues[name]; - }); - return inputValues; - } else { - var newValues = {} - forEach(paramsValue.split(","), function (name) { - name = name.trim(); - newValues[name] = inputValues[name]; - }); - return newValues; - } - } else { - return inputValues; - } - } - - function getSwapSpecification(elt) { - var swapInfo = getClosestAttributeValue(elt, "kt-swap"); - var swapSpec = { - "swapStyle" : kutty.config.defaultSwapStyle, - "swapDelay" : kutty.config.defaultSwapDelay, - "settleDelay" : kutty.config.defaultSettleDelay - } - if (swapInfo) { - var split = splitOnWhitespace(swapInfo); - if (split.length > 0) { - swapSpec["swapStyle"] = split[0]; - for (var i = 1; i < split.length; i++) { - var modifier = split[i]; - if (modifier.indexOf("swap:") === 0) { - swapSpec["swapDelay"] = parseInterval(modifier.substr(5)); - } - if (modifier.indexOf("settle:") === 0) { - swapSpec["settleDelay"] = parseInterval(modifier.substr(7)); - } - } - } - } - return swapSpec; - } - - function issueAjaxRequest(elt, verb, path, eventTarget) { - var target = getTarget(elt); - if (target == null) { - triggerErrorEvent(elt, 'targetError.kutty', {target: getRawAttribute(elt, "kt-target")}); - return; - } - var eltData = getInternalData(elt); - if (eltData.requestInFlight) { - return; - } else { - eltData.requestInFlight = true; - } - var endRequestLock = function(){ - eltData.requestInFlight = false - } - var promptQuestion = getClosestAttributeValue(elt, "kt-prompt"); - if (promptQuestion) { - var prompt = prompt(promptQuestion); - if(!triggerEvent(elt, 'prompt.kutty', {prompt: prompt, target:target})) return endRequestLock(); - } - - var confirmQuestion = getClosestAttributeValue(elt, "kt-confirm"); - if (confirmQuestion) { - if(!confirm(confirmQuestion)) return endRequestLock(); - } - - var xhr = new XMLHttpRequest(); - - var headers = getHeaders(elt, target, prompt, eventTarget); - var rawParameters = getInputValues(elt, verb); - var filteredParameters = filterValues(rawParameters, elt, verb); - - if (verb !== 'get') { - headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - if (verb !== 'post') { - headers['X-HTTP-Method-Override'] = verb.toUpperCase(); - } - } - - var requestConfig = { - parameters: filteredParameters, - unfilteredParameters:rawParameters, - headers:headers, - target:target, - verb:verb - }; - if(!triggerEvent(elt, 'configRequest.kutty', requestConfig)) return endRequestLock(); - - // request type - var requestURL; - if (verb === 'get') { - var noValues = Object.keys(filteredParameters).length === 0; - requestURL = path + (noValues ? "" : "?" + urlEncode(filteredParameters)); - xhr.open('GET', requestURL, true); - } else { - requestURL = path; - xhr.open('POST', requestURL, true); - } - - xhr.overrideMimeType("text/html"); - - // request headers - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - if(headers[header]) xhr.setRequestHeader(header, headers[header]); - } - } - - var eventDetail = {xhr: xhr, target: target}; - xhr.onload = function () { - try { - if (!triggerEvent(elt, 'beforeOnLoad.kutty', eventDetail)) return; - - handleTrigger(elt, this.getResponseHeader("X-KT-Trigger")); - var pushedUrl = this.getResponseHeader("X-KT-Push"); - - var shouldSaveHistory = shouldPush(elt) || pushedUrl; - - if (this.status >= 200 && this.status < 400) { - if (this.status === 286) { - cancelPolling(elt); - } - // don't process 'No Content' response - if (this.status !== 204) { - if (!triggerEvent(elt, 'beforeSwap.kutty', eventDetail)) return; - - var resp = this.response; - - // Save current page - if (shouldSaveHistory) { - saveHistory(); - } - - var swapSpec = getSwapSpecification(elt); - - target.classList.add("kutty-swapping"); - var doSwap = function () { - try { - var settleTasks = swapResponse(swapSpec.swapStyle, target, elt, resp); - target.classList.remove("kutty-swapping"); - target.classList.add("kutty-settling"); - triggerEvent(elt, 'afterSwap.kutty', eventDetail); - - var doSettle = function(){ - forEach(settleTasks, function (settleTask) { - settleTask.call(); - }); - target.classList.remove("kutty-settling"); - // push URL and save new page - if (shouldSaveHistory) { - pushUrlIntoHistory(pushedUrl || requestURL ); - } - triggerEvent(elt, 'afterSettle.kutty', eventDetail); - } - - if (swapSpec.settleDelay > 0) { - setTimeout(doSettle, swapSpec.settleDelay) - } else { - doSettle(); - } - } catch (e) { - triggerErrorEvent(elt, 'swapError.kutty', eventDetail); - throw e; - } - }; - - if (swapSpec.swapDelay > 0) { - setTimeout(doSwap, swapSpec.swapDelay) - } else { - doSwap(); - } - } - } else { - triggerErrorEvent(elt, 'responseError.kutty', eventDetail); - } - } catch (e) { - eventDetail['exception'] = e; - triggerErrorEvent(elt, 'onLoadError.kutty', eventDetail); - throw e; - } finally { - removeRequestIndicatorClasses(elt); - endRequestLock(); - triggerEvent(elt, 'afterOnLoad.kutty', eventDetail); - } - } - xhr.onerror = function () { - removeRequestIndicatorClasses(elt); - triggerErrorEvent(elt, 'sendError.kutty', eventDetail); - endRequestLock(); - } - if(!triggerEvent(elt, 'beforeRequest.kutty', eventDetail)) return endRequestLock(); - addRequestIndicatorClasses(elt); - xhr.send(verb === 'get' ? null : urlEncode(filteredParameters)); - } - - //==================================================================== - // Initialization - //==================================================================== - - function ready(fn) { - if (getDocument().readyState !== 'loading') { - fn(); - } else { - getDocument().addEventListener('DOMContentLoaded', fn); - } - } - - // insert kutty-indicator css rules - addRule(".kutty-indicator{opacity:0;transition: opacity 200ms ease-in;}"); - addRule(".kutty-request .kutty-indicator{opacity:1}"); - addRule(".kutty-request.kutty-indicator{opacity:1}"); - - function mergeMetaConfig() { - var element = getDocument().querySelector('meta[name="kutty-config"]'); - if (element) { - var source = JSON.parse(element.content); - kutty.config = mergeObjects(kutty.config , source) - } - } - - // initialize the document - ready(function () { - mergeMetaConfig(); - var body = getDocument().body; - processNode(body); - triggerEvent(body, 'load.kutty', {}); - window.onpopstate = function () { - restoreHistory(); - }; - }) - - // Public API - return { - onLoad: onLoadHelper, - process: processNode, - on: addKuttyEventListener, - off: removeKuttyEventListener, - trigger : triggerEvent, - find : find, - findAll : findAll, - closest : closest, - remove : removeElement, - addClass : addClassToElement, - removeClass : removeClassFromElement, - toggleClass : toggleClassOnElement, - takeClass : takeClassForElement, - logAll : logAll, - logger : null, - config : { - historyEnabled:true, - historyCacheSize:10, - defaultSwapStyle:'innerHTML', - defaultSwapDelay:0, - defaultSettleDelay:100 - }, - version: "0.0.1", - _:internalEval - } - } -)();
\ No newline at end of file diff --git a/www/posts/2020-5-18-kutty-er-htmx-0.0.2-is-released.md b/www/posts/2020-5-18-kutty-er-htmx-0.0.2-is-released.md new file mode 100644 index 00000000..6b85ec54 --- /dev/null +++ b/www/posts/2020-5-18-kutty-er-htmx-0.0.2-is-released.md @@ -0,0 +1,38 @@ +--- +layout: layout.njk +tags: post +title: htmx 0.0.2 has been released! +--- + +## htmx 0.0.3 Release + +I'm pleased to announce the [0.0.2 release](https://unpkg.com/browse/htmx.org@0.0.3/) of kutty, the successor +to [intercooler.js](http://intercoolerjs.org)! + +#### Why not kutty 0.0.2? + +One of the reasons you put a `0.0.1` release out there is to see what happens. And one of the things that +happened was that multiple people made comments on how the word "kutty" meant different things in different languages, including +"small", "child" and a very unfortunate meaning in dutch slang. I had originally +[called the project `htmx`](https://github.com/bigskysoftware/kutty/commit/b003ccadf855fe49a40ca0b86ca3c9e16448d33c#diff-b9cfc7f2cdf78a7f4b91a753d10865a2) +(html extensions) and went back and forth between the two names for a bit. + +It seems like, upon contact with reality, `htmx` is a better long term name for the project. It's also +a lot easier to search twitter & reddit for that term. + +It's a simple fix for anyone who actually used `0.0.1`: + +* attributes go from `kt-` to `hx-` (their original prefix) +* request headers go from `X-KT-` to `X-HX-` +* `kutty` goes to `htmx` for event names, etc. + +#### Changes + +OK, so besides the big re-rename, what changed? + +* A bug fix for the `hx-prompt` attribute +* A bug fix for multiple `hx-swap-oob` attributes +* Moved the default CSS indicator injection into its own sheet to avoid breaking +* Added the `htmx.config.includeIndicatorStyles` configuration option so people can opt out of injecting the indicator CSS + +Cheers!
\ No newline at end of file diff --git a/www/reference.md b/www/reference.md index 856f5584..98b31560 100644 --- a/www/reference.md +++ b/www/reference.md @@ -1,42 +1,42 @@ --- layout: layout.njk -title: </> kutty - Attributes +title: </> htmx - Attributes --- ## <a name="attributes"></a> [Attribute Reference](#attributes) | Attribute | Description | |-----------|-------------| -| [`kt-boost`](/attributes/kt-boost) | progressively enhances anchors and forms to use AJAX requests -| [`kt-classes`](/attributes/kt-classes) | timed modification of classes on an element -| [`kt-confirm`](/attributes/kt-confirm) | shows a confim() dialog before issuing a request -| [`kt-delete`](/attributes/kt-delete) | issues a `DELETE` to the specified URL -| [`kt-error-url`](/attributes/kt-error-url) | a URL to send client-side errors to -| [`kt-get`](/attributes/kt-get) | issues a `GET` to the specified URL -| [`kt-history-elt`](/attributes/kt-history-elt) | the element to snapshot and restore during history navigation -| [`kt-include`](/attributes/kt-include) | includes additional data in AJAX requests -| [`kt-indicator`](/attributes/kt-indicator) | the element to put the `kutty-request` class on during the AJAX request -| [`kt-params`](/attributes/kt-params) | filters the parameters that will be submitted with a request -| [`kt-patch`](/attributes/kt-patch) | issues a `PATCH` to the specified URL -| [`kt-post`](/attributes/kt-post) | issues a `POST` to the specified URL -| [`kt-prompt`](/attributes/kt-prompt) | shows a prompt before submitting a request -| [`kt-push-url`](/attributes/kt-push-url) | pushes the URL into the location bar, creating a new history entry -| [`kt-put`](/attributes/kt-put) | issues a `PUT` to the specified URL -| [`kt-select`](/attributes/kt-select) | selects a subset of the server response to process -| [`kt-sse-src`](/attributes/kt-sse-src) | establishes an [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) source for events -| [`kt-swap-oob`](/attributes/kt-swap-oob) | marks content in a response as being "Out of Band", i.e. swapped somewhere other than the target -| [`kt-swap`](/attributes/kt-swap) | controls how the response content is swapped into the DOM (e.g. 'outerHTML' or 'beforeEnd') -| [`kt-target`](/attributes/kt-target) | specifies the target element to be swapped -| [`kt-trigger`](/attributes/kt-trigger) | specifies the event that triggers the request +| [`hx-boost`](/attributes/hx-boost) | progressively enhances anchors and forms to use AJAX requests +| [`hx-classes`](/attributes/hx-classes) | timed modification of classes on an element +| [`hx-confirm`](/attributes/hx-confirm) | shows a confim() dialog before issuing a request +| [`hx-delete`](/attributes/hx-delete) | issues a `DELETE` to the specified URL +| [`hx-error-url`](/attributes/hx-error-url) | a URL to send client-side errors to +| [`hx-get`](/attributes/hx-get) | issues a `GET` to the specified URL +| [`hx-history-elt`](/attributes/hx-history-elt) | the element to snapshot and restore during history navigation +| [`hx-include`](/attributes/hx-include) | includes additional data in AJAX requests +| [`hx-indicator`](/attributes/hx-indicator) | the element to put the `htmx-request` class on during the AJAX request +| [`hx-params`](/attributes/hx-params) | filters the parameters that will be submitted with a request +| [`hx-patch`](/attributes/hx-patch) | issues a `PATCH` to the specified URL +| [`hx-post`](/attributes/hx-post) | issues a `POST` to the specified URL +| [`hx-prompt`](/attributes/hx-prompt) | shows a prompt before submitting a request +| [`hx-push-url`](/attributes/hx-push-url) | pushes the URL into the location bar, creating a new history entry +| [`hx-put`](/attributes/hx-put) | issues a `PUT` to the specified URL +| [`hx-select`](/attributes/hx-select) | selects a subset of the server response to process +| [`hx-sse-src`](/attributes/hx-sse-src) | establishes an [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) source for events +| [`hx-swap-oob`](/attributes/hx-swap-oob) | marks content in a response as being "Out of Band", i.e. swapped somewhere other than the target +| [`hx-swap`](/attributes/hx-swap) | controls how the response content is swapped into the DOM (e.g. 'outerHTML' or 'beforeEnd') +| [`hx-target`](/attributes/hx-target) | specifies the target element to be swapped +| [`hx-trigger`](/attributes/hx-trigger) | specifies the event that triggers the request ## <a name="classes"></a> [CSS Class Reference](#classes) | Class | Description | |-----------|-------------| -| `kutty-indicator` | A dynamically generated class that will toggle visible (opacity:1) when a `kutty-request` class is present -| `kutty-request` | Applied to either the element or the element specified with [`kt-indicator`](/attributes/kt-indicator) while a request is ongoing -| `kutty-settling` | Applied to a target after content is swapped, removed after it is settled -| `kutty-swapping` | Applied to a target before any content is swapped, removed after it is swapped +| `htmx-indicator` | A dynamically generated class that will toggle visible (opacity:1) when a `htmx-request` class is present +| `htmx-request` | Applied to either the element or the element specified with [`hx-indicator`](/attributes/hx-indicator) while a request is ongoing +| `htmx-settling` | Applied to a target after content is swapped, removed after it is settled +| `htmx-swapping` | Applied to a target before any content is swapped, removed after it is swapped ## <a name="headers"></a> [HTTP Header Reference](#headers) @@ -46,48 +46,48 @@ title: </> kutty - Attributes | Header | Description | |-------|-------------| | `X-HTTP-Method-Override` | the HTTP verb for non-`GET` and `POST` requests -| `X-KT-Active-Element-Name` | the `name` of the active element if it exists -| `X-KT-Active-Element-Value` | the `value` of the active element if it exists -| `X-KT-Active-Element` | the `id` of the active element if it exists -| `X-KT-Current-URL` | the current URL of the browser -| `X-KT-Event-Target` | the `id` of the original event target -| `X-KT-Prompt` | the user response to an [ic-prompt](/attributes/kt-prompt) -| `X-KT-Request` | always `true` -| `X-KT-Target` | the `id` of the target element if it exists -| `X-KT-Trigger-Name` | the `name` of the triggered element if it exists -| `X-KT-Trigger` | the `id` of the triggered element if it exists +| `X-HX-Active-Element-Name` | the `name` of the active element if it exists +| `X-HX-Active-Element-Value` | the `value` of the active element if it exists +| `X-HX-Active-Element` | the `id` of the active element if it exists +| `X-HX-Current-URL` | the current URL of the browser +| `X-HX-Event-Target` | the `id` of the original event target +| `X-HX-Prompt` | the user response to an [ic-prompt](/attributes/hx-prompt) +| `X-HX-Request` | always `true` +| `X-HX-Target` | the `id` of the target element if it exists +| `X-HX-Trigger-Name` | the `name` of the triggered element if it exists +| `X-HX-Trigger` | the `id` of the triggered element if it exists ### <a name="response_headers"></a> [Response Headers](#response_headers) | Header | Description | |-------|-------------| -| `X-KT-Push` | pushes a new url into the history stack -| [`X-KT-Trigger`](/headers/x-kt-trigger) | allows you to trigger client side events, see the [documentation](/headers/x-kt-trigger) for more info +| `X-HX-Push` | pushes a new url into the history stack +| [`X-HX-Trigger`](/headers/x-hx-trigger) | allows you to trigger client side events, see the [documentation](/headers/x-hx-trigger) for more info ## <a name="events"></a> [Event Reference](#events) | Event | Description | |-------|-------------| -| [`afterOnLoad.kutty`](/events#afterOnLoad.kutty) | triggered after an AJAX request has finished -| [`afterSettle.kutty`](/events#afterSettle.kutty) | triggered after the DOM has settled -| [`afterSwap.kutty`](/events#afterSwap.kutty) | triggered after new content has been swapped in -| [`beforeOnLoad.kutty`](/events#beforeOnLoad.kutty) | triggered before any response processing occurs -| [`beforeRequest.kutty`](/events#beforeRequest.kutty) | triggered before an AJAX request is made -| [`beforeSwap.kutty`](/events#beforeSwap.kutty) | triggered before a swap is done -| [`configRequest.kutty`](/events#configRequest.kutty) | triggered before the request, allows you to customize parameters, headers -| [`historyCacheMiss.kutty`](/events#historyCacheMiss.kutty) | triggered on a cache miss in the history subsystem -| [`historyCacheMissError.kutty`](/events#historyCacheMissError.kutty) | triggered on a unsuccessful remote retrieval -| [`historyCacheMissLoad.kutty`](/events#historyCacheMissLoad.kutty) | triggered on a succesful remote retrieval -| [`historyRestore.kutty`](/events#historyRestore.kutty) | triggered when kutty handles a history restoration action -| [`beforeHistorySave.kutty`](/events#beforeHistorySave.kutty) | triggered before content is saved to the history cache -| [`initSSE.kutty`](/events#initSSE.kutty) | triggered when a new Server Sent Event source is created -| [`load.kutty`](/events#load.kutty) | triggered when new content is added to the DOM -| [`noSSESourceError.kutty`](/events#noSSESourceError.kutty) | triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined -| [`onLoadError.kutty`](/events#onLoadError.kutty) | triggered when an exception occurs during the onLoad handling in kutty -| [`oobErrorNoTarget.kutty`](/events#oobErrorNoTarget.kutty) | triggered when an out of band element does not have a matching ID in the current DOM -| [`prompt.kutty`](/events#prompt.kutty) | triggered after a prompt is shown -| [`responseError.kutty`](/events#responseError.kutty) | triggered when an HTTP response error (non-`200` or `300` response code) occurs -| [`sendError.kutty`](/events#sendError.kutty) | triggered when a network error prevents an HTTP request from happening -| [`sseError.kutty`](/events#sseError.kutty) | triggered when an error occurs with a SSE source -| [`swapError.kutty`](/events#swapError.kutty) | triggered when an error occurs during the swap phase -| [`targetError.kutty`](/events#targetError.kutty) | triggered when an invalid target is specified +| [`afterOnLoad.htmx`](/events#afterOnLoad.htmx) | triggered after an AJAX request has finished +| [`afterSettle.htmx`](/events#afterSettle.htmx) | triggered after the DOM has settled +| [`afterSwap.htmx`](/events#afterSwap.htmx) | triggered after new content has been swapped in +| [`beforeOnLoad.htmx`](/events#beforeOnLoad.htmx) | triggered before any response processing occurs +| [`beforeRequest.htmx`](/events#beforeRequest.htmx) | triggered before an AJAX request is made +| [`beforeSwap.htmx`](/events#beforeSwap.htmx) | triggered before a swap is done +| [`configRequest.htmx`](/events#configRequest.htmx) | triggered before the request, allows you to customize parameters, headers +| [`historyCacheMiss.htmx`](/events#historyCacheMiss.htmx) | triggered on a cache miss in the history subsystem +| [`historyCacheMissError.htmx`](/events#historyCacheMissError.htmx) | triggered on a unsuccessful 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 +| [`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 +| [`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 +| [`oobErrorNoTarget.htmx`](/events#oobErrorNoTarget.htmx) | triggered when an out of band element does not have a matching ID in the current DOM +| [`prompt.htmx`](/events#prompt.htmx) | triggered after a prompt is shown +| [`responseError.htmx`](/events#responseError.htmx) | triggered when an HTTP response error (non-`200` or `300` response code) occurs +| [`sendError.htmx`](/events#sendError.htmx) | triggered when a network error prevents an HTTP request from happening +| [`sseError.htmx`](/events#sseError.htmx) | triggered when an error occurs with a SSE source +| [`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 diff --git a/www/talk.md b/www/talk.md index 27a1804b..f5dc69b9 100644 --- a/www/talk.md +++ b/www/talk.md @@ -1,21 +1,21 @@ --- layout: layout.njk -title: </> kutty - high power tools for html +title: </> htmx - high power tools for html --- -## Kutty Talk +## Htmx Talk -Right now the best place to talk about kutty is the [intercooler gitter room](https://gitter.im/intercooler-js/Lobby) +Right now the best place to talk about htmx is the [intercooler gitter room](https://gitter.im/intercooler-js/Lobby) I'll be setting up a forum and chat room at some point. ## Features & Bug Reports -[https://github.com/bigskysoftware/kutty/issues](https://github.com/bigskysoftware/kutty/issues) +[https://github.com/bigskysoftware/htmx/issues](https://github.com/bigskysoftware/htmx/issues) ## Twitter -[@kutty_org](https://twitter.com/kutty_org) +[@htmx_org](https://twitter.com/htmx_org) ## Blog & Announcements |